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

时间:2015-06-11 11:17:39

标签: sql postgresql

我需要使用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                                                 

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

1 个答案:

答案 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