我有一张这样的桌子:
amount type app owe
1 a 10 10
2 a 8 -2
3 a 20 12
4 i 30 10
5 a 40 10
欠款额是:
(type == 'a')?app - sum(owe) where amount < (amount for current row):max(app-sum(owe)where amount<(amount for current row),0)
所以我需要在窗口功能所在的列上有一个窗口功能。在没有限制的前一行和前一行之间的行之间的行上有这些分区,但是它必须在不同的列上,而不是我正在累加的列上。有没有办法引用窗口功能所在的同一列
我尝试了一个别名
case
when type = a
then app - sum(owe)over(ROWS BETWEEN UNBOUNDED PRECEDING AND 1 preceding) as owe
else
greatest(0,app - sum(owe)over(ROWS BETWEEN UNBOUNDED PRECEDING AND 1 preceding))
end as owe
但是由于欠债在我付清时不存在,所以我得到:
欠费不存在。
还有其他方法吗?
答案 0 :(得分:0)
您无法使用窗口功能执行此操作。使用SQL的唯一机会是递归CTE:
WITH RECURSIVE tab_owe AS (
SELECT amount, type, app,
CASE WHEN type = 'a'
THEN app
ELSE GREATEST(app, 0)
END AS owe
FROM tab
ORDER BY amount LIMIT 1
UNION ALL
SELECT t.amount, t.type, t.app,
CASE WHEN t.type = 'a'
THEN t.app - sum(tab_owe.owe)
ELSE GREATEST(t.app - sum(tab_owe.owe), 0)
END AS owe
FROM (SELECT amount, type, app
FROM tab
WHERE amount > (SELECT max(amount) FROM tab_owe)
ORDER BY amount
LIMIT 1) AS t
CROSS JOIN tab_owe
GROUP BY t.amount, t.type, t.app
)
SELECT amount, type, app, owe
FROM tab_owe;
(未经测试)
用程序代码编写起来会容易得多,因此请考虑使用表函数。
答案 1 :(得分:0)
这是我想出的。当然,我不是一个真正的程序员,所以我确定有一种更聪明的方法:
insert into mort (amount, "type", app)
values
(1,'a',10),
(2,'a',8),
(3,'a',20),
(4,'i',30),
(5,'a',40)
CREATE OR REPLACE FUNCTION mort_v ()
RETURNS TABLE (
zamount int,
ztype text,
zapp int,
zowe double precision
) AS $$
DECLARE
var_r record;
charlie double precision;
sam double precision;
BEGIN
charlie = 0;
FOR var_r IN(SELECT
amount,
"type",
app
FROM mort order by 1)
LOOP
zamount = var_r.amount;
ztype = var_r.type;
zapp = var_r.app;
sam = var_r.app - charlie;
if ztype = 'a' then
zowe = sam;
else
zowe = greatest(sam, 0);
end if;
charlie = charlie + zowe;
RETURN NEXT;
END LOOP;
END; $$
LANGUAGE 'plpgsql';
select * from mort_v()
因此,由于我的技能有限,您会发现我不得不在表中已存在的列前面添加一个“ z”,以便再次将其吐出。如果表有30列,则通常必须执行30次。但是,我问了一位真正的工程师,他提到如果您只将主键与计算出的列一起吐出,就可以将其重新连接到原始表中。那比我拥有的要聪明。如果有更好的解决方案,那就太好了。确实可以很好地说明如何在postgre中执行类似游标的操作,以及如何在mssqlserver中像前面那样在不使用'@'的情况下进行变量。