简体   繁体   English

PostgreSQL中的转置表

[英]Transpose table in PostgreSQL

I have a table in PostgreSQL like: 我在PostgreSQL中有一张表格,例如:

org_name | month_1 | month_2 | ... | month_12
---------------------------------------------
org1     |  20     |   30    | ... |  15
org2     |  34     |   27    | ... |  49

I need to transpose it to: 我需要将其转置为:

month  |  org1 | org2 
----------------------
   1   |   20  | 34
   2   |   30  | 27
..     |   ..  | ..
  12   |   15  | 49

I found next solution on stackoverflow: 我在stackoverflow上找到了下一个解决方案:

SELECT
    *
FROM 
    (select org_name, monthes, value
    from my_table
    unpivot
    (
        value
        for monthes in (month_2, month_3, month_4, month_5, month_6, month_7, month_8, month_9, month_10, month_11, month_12)
    ) unpiv
    ) src
    pivot
    ( 
        sum(value)
        for org_name in ('org1', 'org2')
    ) piv

But it doesn't work with syntax error about 'for'. 但这不适用于有关“ for”的语法错误。 Where I'm wrong? 我哪里错了?

I've not been able to get your approach to work yet; 我还没办法使您工作。 but this multistep union seems to. 但是这种多步骤的结合似乎可以做到。

cte (mo, Org1, Org2) as (
SELECT 1, case when org_name = 'org1' then month_1 end as Org1, case when org_name = 'org2' then month_1 end as Org2 from myTable UNION ALL
SELECT 2, case when org_name = 'org1' then month_2 end as Org1, case when org_name = 'org2' then month_2 end as Org2 from myTable UNION ALL
SELECT 3, case when org_name = 'org1' then month_3 end as Org1, case when org_name = 'org2' then month_3 end as Org2 from myTable UNION ALL
...
SELECT 12, case when org_name = 'org1' then month_12 end as Org1, case when org_name = 'org2' then month_12 end as Org2 from myTable)
SELECT mo, max(org1) org1, max(org2) org2 
FROM  cte
GROUP BY mo

Maybe you would find unnest more palpable: 也许您会发现嵌套更加明显:

With myTable (org_name, month_1, Month_2, month_3, Month_12) as (
    Select 'org1',20,30,40,15 union all
    Select 'org2',34,27,45,49),

cte  (Mo,Org1,org2) as(select unnest(ARRAY[1,2,3,12]) AS Mo
     , case when org_name='org1' then unnest(ARRAY[month_1, Month_2,month_3,Month_12]) end as Org1
     , case when org_name='org2' then unnest(ARRAY[month_1, Month_2,month_3,Month_12]) end as Org2
     from mytable)

     Select mo,sum(org1) org1, sum(org2) org2
     From cte
     group by mo

Actually, you need something like unpivot plus pivot here. 实际上,您需要在此处像“无枢轴枢轴”之类的东西。

1. decompose the rows to get single entries per month ("unpivot"): 1.分解行以每月获取单个条目(“取消透视”):

SELECT mon, org_name, val
FROM   tbl, LATERAL (
   VALUES
      (1, month_1)
    , (2, month_2)
    -- ... more
    , (12, month_12)
   ) x(mon, val)
ORDER  BY 1, 2;

If there are more organizations, you have to add a WHERE clause to pick the relevant ones: 如果组织更多,则必须添加WHERE子句以选择相关的组织:

WHERE  org_name IN ('org1', 'org2')

2. , feed this to crosstab() to get your desired result: 2. ,将其提供给crosstab()以获得所需的结果:

SELECT *
FROM   crosstab($$
      SELECT mon, org_name, val
      FROM   tbl, LATERAL (
         VALUES
            (1, month_1)
          , (2, month_2)
          -- ... more
          , (12, month_12)
         ) x(mon, val)
      WHERE  org_name IN ('org1', 'org2')
      ORDER  BY 1, 2$$)
   AS ct (month int, org1 int, org2 int);

Voilá. Voilá。

The crosstab() function is provided by the additional module tablefunc , so this has to be installed. crosstab()函数由附加模块tablefunc ,因此必须安装它。
Detailed instructions and links: 详细说明和链接:

Automation: 自动化:

Here is a basic function to build the SQL statement for any list of organizations and any list of months: 这里是构建组织任何列表和个月的任何列表SQL语句中的基本功能:

CREATE OR REPLACE FUNCTION f_unpivot_colums(_orgs text[], _months int[])
  RETURNS text AS
$func$
SELECT 'SELECT *
FROM   crosstab($$
   SELECT x.mon, t.org_name, x.val
   FROM   tbl t, LATERAL (
      VALUES '
       || string_agg(format('(%s, t.%I)', m, 'month_' || m), ', ')
       || ') x(mon, val)
   WHERE  t.org_name = ANY (' || quote_literal(_orgs) || ')
   ORDER  BY 1, 2$$)
AS ct (month int, org1 int, org2 int)'
FROM   unnest(_months) m
$func$  LANGUAGE sql;

You can extract the list of organizations or months dynamically, too ... 您也可以动态提取组织或月份列表...

Call: 呼叫:

SELECT f_unpivot_colums('{org1, org2}', '{1,2,12}')

Produces above statement - which you can execute in turn. 产生以上语句-您可以依次执行。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM