2017-01-09 16 views
2

我在Postgres中有一個表,用於捕獲非結構化形式的信息並重建它。我需要在從該表導出數據時重新應用一些結構,並且掙扎。在PostgreSQL中將任意多行轉換爲列

目前,我有以下形式的表:

lbl | name  | value 
----|------------|-------- 
1 | num  |  1 
1 | colour  | "Red" 
1 | percentage | 25.0 
2 | num  |  2 
2 | colour  | "Green" 
2 | percentage | 50.0 
3 | num  |  3 
3 | colour  | "Blue" 
3 | percentage | 75.0 

,我需要產生這種形式的表格:

lbl | num | colour | percentage 
----|-----|---------|------------ 
1 | 1 | "Red" | 25.0 
2 | 2 | "Green" | 50.0 
3 | 3 | "Blue" | 75.0 

我已經建立了這個查詢:

SELECT lbl, 
    max(case when name = 'num' then value else '-' end) num, 
    max(case when name = 'colour' then value else '-' end) colour, 
    max(case when name = 'percentage' then value else '-' end) percentage 
FROM example_table 
GROUP BY lbl 

查詢工作正常,但我需要將其擴展爲包含任意數量的名稱潛在值。我調查了crossfunc,但無法按照我的意圖使其工作。任何幫助將不勝感激。

我已經成立了一個sqlfiddle這裏是爲了幫助踢東西了:http://sqlfiddle.com/#!9/8d3133/6/0

編輯:我可以用PL/pgSQL的同時如果能夠。

+0

我想你需要在這裏使用動態SQL。 –

+0

「*包含任意數量的名稱*的潛在值」,這在普通SQL中是不可能的。運行查詢的數據庫_before_必須知道查詢的列數。 –

+0

啊,好的。如果我有權訪問使用plsql可以工作嗎? – George

回答

4

在Postgres的透視表中,主要問題是,一個查詢的結果結構(數和列的名稱)可根據所選擇的數據不改變。可能的解決方案之一是動態創建一個視圖,該數據定義了哪個結構。該示例函數創建基於該表example_table視圖:

create or replace function create_pivot_view() 
returns void language plpgsql as $$ 
declare 
    list text; 
begin 
    select string_agg(format('jdata->>%1$L "%1$s"', name), ', ') 
    from (
     select distinct name 
     from example_table 
     ) sub 
    into list; 

    execute format($f$ 
     drop view if exists example_pivot_view; 
     create view example_pivot_view as 
     select lbl, %s 
     from (
      select lbl, json_object_agg(name, value) jdata 
      from example_table 
      group by 1 
      order by 1 
      ) sub 
     $f$, list); 
end $$; 

使用表被修改後(可能在觸發器)的函數和查詢創建的視圖:

select create_pivot_view(); 

select * 
from example_pivot_view; 

lbl | num | colour | percentage 
-----+-----+--------+------------ 
    1 | 1 | Red | 25.0 
    2 | 2 | Green | 50.0 
    3 | 3 | Blue | 75.0 
(3 rows) 

Test it here.

請注意,只有在向表中添加新名稱(或已刪除某個名稱)之後,才需要重新創建視圖(調用函數)。如果不同名稱的集合沒有更改,則可以查詢該視圖而不重新創建它。如果設置經常被修改,創建一個臨時視圖將是一個更好的選擇。

您可能也有興趣Flatten aggregated key/value pairs from a JSONB field?

+1

併發性如何?將'create view example_pivot_view as'更改爲''將'example_pivot_view cursor'聲明爲''並且'select * from example_pivot_view;'''從'example_pivot_view''中獲取所有內容'' - 這會更安全。 – Abelisto

+0

遊標是個好主意。我不建議這樣做,主要是因爲正確使用遊標的一般知識很少,對於普通讀者來說,解決方案很難。 – klin

+0

謝謝,那工作得很好。我首先測試了視圖,然後用光標測試了兩者。我們的工具還有其他一些與遊標配合使用的組件,所以我並不完全不熟悉它們。 – George

0

嘗試這種

select 
tab.ibl, 
t1_num.value as "num", 
t2_color.value as "colour", 
t3_perc.value as "percentage" 
from 
(
    select distinct ibl from your_table order by tab.ibl desc 
) tab 
left join your_table t1_num on t1_num.ibl = tab.ibl and t1_num.name = 'num' 
left join your_table t2_color on t2_color.ibl = tab.ibl and t2_color.name = 'colour' 
left join your_table t3_perc on t3_perc.ibl = tab.ibl and t3_perc.name = 'percentage' 
+0

感謝您的回覆,但這仍然需要知道名稱列的潛在值是否超前。 – George