Tii*_*mel 6 postgresql window-functions
我想从前一行减法结果中动态减去,作为输入,我想给出一个数字。
我有桌子 a
CREATE TABLE a (id int, code text, qty numeric);
Run Code Online (Sandbox Code Playgroud)
还有里面的数据
INSERT INTO a (id,code,qty)
(1,'test',5),
(2,'test',3),
(3,'test',10);
Run Code Online (Sandbox Code Playgroud)
1.sample - 当输入是16
- 期望的结果是:
id | qty
--------------
1 | 0
2 | 0
3 | 2
Run Code Online (Sandbox Code Playgroud)
计算将是这样的
case when 16 > 5 then 16-5 else 5-16 end /* result 11, but displayed 0 */
case when 11 > 3 then 11-3 else 3-11 end /* result 8, but displayed 0 */
case when 8 > 10 then 8-10 else 10-8 end /* result 2 and displayed 2 */
Run Code Online (Sandbox Code Playgroud)
2.sample - 当输入是6
- 期望的结果是:
id | qty
--------------
1 | 0
2 | 2
3 | 10 /* is optional to display */
Run Code Online (Sandbox Code Playgroud)
计算将是这样的
case when 6 > 5 then 6-5 else 5-6 end /* result 1, but displayed 0 */
case when 1 > 3 then 1-3 else 3-1 end /* result 2 and displayed 2 */
case when ... end /* result 10, since input is fulfilled */
Run Code Online (Sandbox Code Playgroud)
从根本上说,这是一个运行总计问题:对于每一行,您都会得到qty的运行总计并从中减去一个固定值。更具体地说,这是关于您希望如何使用运行总计。在这种情况下,您希望根据先前计算的结果显示新的数量值。这里基本上有三种情况:
第一种情况意味着提供的固定值比用尽当前运行总数所必需的多——换句话说,它用尽了从开始到当前行(包括当前行)的所有qty值。因此,我们用 0 代替qty。
在第二种情况下,我们只保留qty,因为现在运行总数超过了固定值,差值大于当前qty - 所以后者保持不变。
最后一种情况是固定值要么完全涵盖到目前为止的所有qty值,要么略小于总数但不少于:直到当前qty 的数量。在这种情况下,我们显示运行总计和固定值之间的差异。
上面的 SQL 是这样的:
SELECT
id,
CASE
WHEN balance < 0 THEN 0
WHEN balance > qty THEN qty
ELSE balance
END AS qty
FROM
(
SELECT
id,
qty,
SUM(qty) OVER (ORDER BY id ASC) - @fixedSum AS balance
FROM
a
) AS derived
;
Run Code Online (Sandbox Code Playgroud)
其中@fixedSum是您要从运行总数中减去的固定值。
解决方案的核心部分是SUM(qty) OVER (ORDER BY id ASC)
- 窗口聚合函数来获取qty的运行总数。
我在嵌套的 SELECT 中计算运行总数,因为减法的结果需要在 CASE 表达式中多次引用,并且您不能在同一级别引用计算列,您需要为此使用嵌套。嵌套可以采用派生表或公用表表达式 (CTE) 的形式。上述解决方案使用派生表。
不过,有一种方法可以避免嵌套,并使用函数 LEAST 和 GREATEST 在单个 SELECT 中完成所有计算:
SELECT
id,
qty,
LEAST(
qty,
GREATEST(
SUM(qty) OVER (ORDER BY id ASC) - @fixedSum,
0
)
) AS balance
FROM
a
Run Code Online (Sandbox Code Playgroud)
但是,与使用 CASE 的方法相比,此方法要简单得多。在性能方面,它可能会起作用。
该方法是这样工作的。首先,您使用 GREATEST 函数选择减法结果和 0 之间的较大值。因此,就上面列出的情况而言,如果我们有情况 1,则 GREATEST 将产生 0。非零结果意味着我们有其他情况之一。
然后将获得的值与当前数量进行比较,这次使用 LEAST 函数选择两者中较小的一个。如果我们之前获得 0,则 LEAST 会保留它。如果我们有减法结果并且现在发现它大于qty,则 LEAST 函数会给我们qty(这意味着这是案例 3)。如果差异恰好小于qty,那就是 LEAST 将产生的结果(案例 2)。
归档时间: |
|
查看次数: |
2809 次 |
最近记录: |