我需要使用PostgresSql。我得到下表称钱作为输入
Cash | Adhoc | Collateral | Total
---------------------------------
20 | 30 | 40 | 90
32 | 12 | 40 | 84
10 | 12 | 40 | 62
13 | 20 | 50 | 83
顾名思义,总数是该行的现金,临时和抵押价值的总和。
我需要以下输出表
ChangeType | ChangeAmount
---------------------------
Cash | 12
Adhoc | -18
Cash | -22
Cash | 3
Adhoc | 8
Collateral | 10
这是第1阶段。在下一阶段,将添加一个名为clientId的新列,并为每个特定客户端显示这些更改。 假设client1是第1行,客户端2是第2行和第3行,然后client1再次是第4行。然后将使用row1和row4形成client1的比较表。
输出表将是
ChangeType | ChangeAmount | ClientId
------------------------------------------
Cash | 7 | client1
Adhoc | -10 | client1
Collateral | 10 | client1
Cash | -22 | client2
我已经能够实现什么是什么时候#34;只有一列"正在使用
在行之间进行更改SELECT
CASE WHEN ( (Cash - lag(Cash, 1)
OVER ( PARTITION BY clientId
) ) != 0)
THEN CAST('Cash' AS Text)
WHEN ( (Adhoc - lag(Adhoc, 1)
OVER ( PARTITION BY clientId
) ) != 0)
THEN CAST('Adhoc' AS Text)
WHEN ( (Collateral - lag(Collateral, 1)
OVER ( PARTITION BY clientId
) ) != 0)
THEN CAST('Collateral' AS Text)
END,
Total - lag(Total,1)
OVER ( PARTITION BY clientId )
FROM money
然而,我失去了如何显示连续更改的多列的更改。
答案 0 :(得分:2)
在某些情况下,过程方法比纯SQL容易得多。我想是这样的。尝试以下功能:
create or replace function show_money_changes()
returns table (change_type text, change_amount integer)
language plpgsql
as $$
declare
prev record;
curr record;
frst boolean = true;
begin
for curr in select * from money --order by id
loop
if not frst then
if curr.cash <> prev.cash then
return query select 'cash'::text, curr.cash - prev.cash;
end if;
if curr.adhoc <> prev.adhoc then
return query select 'adhoc'::text, curr.adhoc - prev.adhoc;
end if;
if curr.collateral <> prev.collateral then
return query select 'collateral'::text, curr.collateral - prev.collateral;
end if;
end if;
prev = curr;
frst = false;
end loop;
end $$;
select * from show_money_changes()
注意:您应该在id
表中有一列(例如money
),以明确排序行。
纯SQL解决方案(假设该表具有连续数字的id列):
select * from (
select
unnest(array['cash', 'adhoc', 'collateral']) change_type,
unnest(array[m2.cash- m1.cash, m2.adhoc- m1.adhoc, m2.collateral- m1.collateral]) change_value
from money m1
join money m2 on m1.id+ 1 = m2.id
) alias
where change_value <> 0
你必须改变条件
on m1.id+ 1 = m2.id
(根据您的实际表定义,将当前行与 next 行连接起来)。
您可以将row_number()
用于此目的。假设event_time
是要按顺序排列的列,然后是:
with money_with_row_numbers as (
select *, row_number() over (order by event_time) rn
from money)
select * from (
select
unnest(array['cash', 'adhoc', 'collateral']) change_type,
unnest(array[m2.cash- m1.cash, m2.adhoc- m1.adhoc, m2.collateral- m1.collateral]) change_value
from money_with_row_numbers m1
join money_with_row_numbers m2 on m1.rn+ 1 = m2.rn
) alias
where change_value <> 0