Postgresql

如何在 PostgreSQL 9.5 中旋轉多個列?

  • February 3, 2022

我有如下範例數據,想看看在這種情況下是否可以使用交叉表函式。

樣本數據:

ITEM   | CD | TYPE |PARTS |  PART | CNT |
Item 1 | A  | AVG  |2     |  1    | 10  |
Item 1 | A  | AVG  |2     |  2    | 20  |
Item 1 | B  | AVG  |2     |  1    | 10  |
Item 1 | B  | AVG  |2     |  2    | 20  |
Item 1 | A  | SUM  |2     |  1    | 10  |
Item 1 | A  | SUM  |2     |  2    | 20  |
Item 1 | B  | SUM  |2     |  1    | 10  |
Item 1 | B  | SUM  |2     |  2    | 20  |

預期結果:

ITEM   | CD | AVG_1 | SUM_1 | AVG_2 | SUM_2 |   

Item 1 |  A | 10    | 10    | 20    | 20    |

Item 1 |  B | 10    | 10    | 20    | 20    |

此外,如果部分為 3,則 A 和 B 程式碼的 AVG 和 SUM 將額外增加一行。這是動態的,使用者可以輸入此值。如何將多行展平?

在此要求中,項目 1 和程式碼 A 必須顯示第 1 部分總和和平均值,然後顯示第 2 部分總和和平均值,這可以根據部分列中的值進行更改。

感謝您對此的幫助!

以下查詢產生了我需要的結果。但是,如果有超過 2 個部分(數據庫列的一部分),則需要動態生成附加列 AVG3、SUM3。

select a.ITEM, a.CD, a.AVG1, b.SUM1, a.AVG2, b.SUM2
from ( SELECT substr(row_name,1,POSITION('|' IN row_name)-1) as item
             substr(row_name,POSITION('|' IN row_name)+1,99) as cd,
             AVG1,
             AVG2
        FROM crosstab('SELECT item||''|''||cd, part::text, cnt::text 
                         FROM a 
                        WHERE type = ''AVG'' 
                       order by item, cd, part',1) 
          AS ct (row_name text, AVG1 text, AVG2 text)
    ) a,
   ( SELECT substr(row_name,1,POSITION('|' IN row_name)-1) as name,
            substr(row_name,POSITION('|' IN row_name)+1,99) as cd,
            SUM1,
            SUM2
       FROM crosstab('SELECT item||''|''||cd, part::text, cnt::text 
                        FROM a
                       WHERE type = ''SUM'' 
                      order by item, cd, part',1) 
         AS ct (row_name text, SUM1 text, SUM2 text)
   ) b
where a.item = b.item
 and a.cd = b.cd;

我更喜歡使用過濾聚合而不是相當繁瑣(在我看來)的crosstab()功能:

select item, 
      cd,
      avg(cnt) filter (where type = 'AVG' and part = 1) as avg_1,
      sum(cnt) filter (where type = 'SUM' and part = 1) as sum_1,
      avg(cnt) filter (where type = 'AVG' and part = 2) as avg_2,
      sum(cnt) filter (where type = 'SUM' and part = 2) as sum_2
from the_table
group by item, cd
order by item, cd       

我認為這也使添加新列更容易。

引用自:https://dba.stackexchange.com/questions/245186