2015-06-11 49 views
5

我需要使用PostgresSql。我如下表叫錢作爲輸入顯示兩行之間變化的所有列

Cash | Adhoc | Collateral | Total 
--------------------------------- 
20 | 30 | 40  | 90 
32 | 12 | 40  | 84 
10 | 12 | 40  | 62 
13 | 20 | 50  | 83 

正如其名,一共是現金,即席與該行的抵押品價值的總和。

我所需要的follwing輸出表

ChangeType | ChangeAmount 
--------------------------- 
    Cash |  12 
    Adhoc |  -18 
    Cash |  -22 
    Cash |  3 
    Adhoc |  8 
Collateral |  10 

這是階段1在下一階段中,一個叫的clientId新列是要添加,並且這些變化都被示出爲每個特定的客戶端。 假設客戶端1是第1行,客戶端2是第2和第3行,然後客戶端1又是第4行。然後,使用row1和row4形成client1的比較表。

輸出表將

ChangeType | ChangeAmount | ClientId 
------------------------------------------ 
    Cash  |  7  | client1 
    Adhoc  |  -10  | client1 
Collateral |  10  | client1 
    Cash  |  -22  | client2 

我以

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

謝謝。在查詢層面完成unpivoting還是需要編寫soci C++代碼? –

+0

如果在SQL級別上不實用,我會感到非常驚訝。提供可用的,完整的示例數據作爲CREATE TABLE和INSERT語句(最好是http://sqlfiddle.com),我會看一看,但我不想自己編寫虛擬數據。 –

回答

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 

(加入當前根據您的實際表格定義,行下一個行)。

您可以使用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 
+0

我有一個時間戳列來排序行。我沒有在這裏顯示,因爲我覺得(雖然有​​爭議),它沒有增加太多的問題 –

+0

@PranavKapoor - 所以在選擇中添加正確的'order by'。 – klin

相關問題