显示两行之间更改的所有列

Pra*_*oor 5 sql postgresql

我需要使用PostgresSql.我得到下表称钱作为输入

Cash | Adhoc | Collateral | Total
 ---------------------------------
 20  |   30  |    40      |   90
 32  |   12  |    40      |   84
 10  |   12  |    40      |   62
 13  |   20  |    50      |   83
Run Code Online (Sandbox Code Playgroud)

顾名思义,总和是该行的现金,临时和抵押价值的总和.

我需要以下输出表

ChangeType  |  ChangeAmount
---------------------------
    Cash    |       12
    Adhoc   |      -18
    Cash    |      -22
    Cash    |       3
    Adhoc   |       8
 Collateral |       10
Run Code Online (Sandbox Code Playgroud)

这是阶段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
Run Code Online (Sandbox Code Playgroud)

通过使用"行只有一列"在行之间切换时,我已经能够实现什么是chaging

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                                                 
Run Code Online (Sandbox Code Playgroud)

然而,我失去了如何显示连续更改的多列的更改.

kli*_*lin 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()
Run Code Online (Sandbox Code Playgroud)

注意:表中应该有一列(例如idmoney来明确地对行进行排序。


纯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
Run Code Online (Sandbox Code Playgroud)

你必须改变条件

on m1.id+ 1 = m2.id
Run Code Online (Sandbox Code Playgroud)

(将当前行与下一行连接起来行连接)根据您的实际表定义。

您可以用于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
Run Code Online (Sandbox Code Playgroud)