【问题标题】:Postgresql pivot? Crosstab?Postgresql支点?交叉表?
【发布时间】:2011-06-15 23:37:00
【问题描述】:

我在 postgres 中有一个表(这是查询的结果),它有一组行(复杂的数据求和的结果),如下所示:(列名是每天的名称, 并且每一列的值都是双精度的。)

周日 周一 周二 周三 周四 周五
1.24   1.11   4.51   3.21    2.21    1.01

我需要从一行中选择数据,因此结果如下所示:

天   金额
周日 1.24
周一 1.11
周二 4.51
周三 3.21
周四 2.21
周五      1.01

刚开始我遇到了困难,因为我确实需要将列名更改为值并旋转结果。我尝试使用交叉表进行试验,但我不完全确定这是我需要的。任何可以让我朝着正确方向前进的建议或建议将不胜感激。

【问题讨论】:

标签: sql postgresql


【解决方案1】:

修改@Jack Douglas 的第一个答案:

SELECT unnest(array['sun', 'mon', 'tue', 'wed', 'thu', 'fri']) AS day,
       unnest(array[sun, mon, tue, wed, thu, fri]) AS amount
FROM t;

根据 9.0 查询规划器,成本要低一些:

Seq Scan on t (cost=0.00..11.62 rows=360 width=192)

Subquery Scan on z (cost=0.00..12.16 rows=360 width=68) -> Seq Scan on t (cost=0.00..11.26 rows=360 width=192)

【讨论】:

    【解决方案2】:

    测试对象:

    create table t ( sun numeric, 
                     mon numeric, 
                     tue numeric, 
                     wed numeric, 
                     thu numeric, 
                     fri numeric );
    
    insert into t(sun, mon, tue, wed, thu, fri)
    values(1.24, 1.11, 4.51, 3.21, 2.21, 1.01);
    

    在没有union 的情况下替代@Unreason 的答案:

    select day[i], amount[i]
    from ( select generate_series(1,6) as i, 
                  array['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri'] as day, 
                  array[sun, mon, tue, wed, thu, fri] as amount
           from t ) z;
    

    如果你需要更通用,你可以这样做:

    create or replace function unpivot(t) returns setof record 
                               language plpgsql immutable strict as $$
    declare
      q record;
      r record;
    begin
      for q in ( select attname, attnum 
                 from pg_attribute 
                 where attnum>0 and attrelid = ( select oid 
                                                 from pg_class 
                                                 where relname = 't' ) ) loop 
        for r in execute 'select '''||q.attname||'''::text, '||
                                 '('||$1::text||'::t).'||q.attname||'::numeric' loop
          return next r;
        end loop;
      end loop;
      return;
    end;$$;
    
    select *
    from unpivot((select row(t.*)::t from t)) 
           as foo(day text, amount numeric);
    

    您可以在 8.4 中使用 using 子句在 execute 中更简洁一些,但我无法在 8.3 上进行测试

    【讨论】:

      【解决方案3】:

      我不知道直接实现,但也许像 http://www.mail-archive.com/dhis2-users@lists.launchpad.net/msg00109.html 这样的东西可以让你开始

      当然,如果您不需要灵活的解决方案,您也可以这样做

      SELECT 'Sun' AS Day, Sun AS Value FROM TABLE WHERE ...
      UNION ALL
      SELECT 'Mon' AS Day, Mon AS Value FROM TABLE WHERE ...
      UNION ALL
      SELECT 'Tue' AS Day, Tue AS Value FROM TABLE WHERE ...
      UNION ALL
      SELECT 'Wed' AS Day, Wed AS Value FROM TABLE WHERE ...
      UNION ALL
      SELECT 'Thu' AS Day, Thu AS Value FROM TABLE WHERE ...
      UNION ALL
      SELECT 'Fri' AS Day, Fri AS Value FROM TABLE WHERE ...
      

      (星期六?)

      【讨论】:

        猜你喜欢
        • 2011-03-01
        • 2022-01-21
        • 2021-07-23
        • 2013-09-16
        相关资源
        最近更新 更多