交叉表转置查询请求

时间:2015-10-12 03:35:23

标签: sql postgresql pivot crosstab

使用Postgres 9.3.4,我有这张表:

create table tbl1(country_code text, metric1 int, metric2 int, metric3 int);
insert into tbl1 values('us', 10, 20, 30);
insert into tbl1 values('uk', 11, 21, 31);
insert into tbl1 values('fr', 12, 22, 32);

我需要一个交叉表查询将其转换为:

create table tbl1(metric text, us int, uk int, fr int);
insert into tbl1 values('metric1', 10, 11, 12);
insert into tbl1 values('metric2', 20, 21, 22);
insert into tbl1 values('metric3', 30, 31, 32);

作为一个额外的奖励,我喜欢汇总:

create table tbl1(metric text, total int, us int, uk int, fr int);
insert into tbl1 values('metric1', 33, 10, 11, 12);
insert into tbl1 values('metric2', 63, 20, 21, 22);
insert into tbl1 values('metric3', 93, 30, 31, 32);

我已经完成了对交叉表规范的盯着,我已经用case语句编写了它,但是它很疯狂且很长,所以能够熟练使用交叉表的人请快速查询以便我继续前进吗?

1 个答案:

答案 0 :(得分:0)

特别困难的是您的数据尚未准备好进行交叉制表。您需要 row_name category value 形式的数据。您可以使用UNION查询获取该信息:

SELECT 'metric1' AS metric, country_code, metric1 FROM tbl1
UNION ALL
SELECT 'metric2' AS metric, country_code, metric2 FROM tbl1
UNION ALL
SELECT 'metric3' AS metric, country_code, metric3 FROM tbl1
ORDER  BY 1, 2 DESC;

但智能LATERAL查询只需要一次表扫描就会更快:

SELECT x.metric, t.country_code, x.val
FROM   tbl1 t
     , LATERAL (VALUES
         ('metric1', metric1)
       , ('metric2', metric2)
       , ('metric3', metric3)
       ) x(metric, val)
ORDER  BY 1, 2 DESC;

相关:

使用带有此参数的1个参数的crosstab()的简单形式作为输入:

SELECT * FROM crosstab(
 $$SELECT x.metric, t.country_code, x.val
   FROM   tbl1 t
        , LATERAL (VALUES
            ('metric1', metric1)
          , ('metric2', metric2)
          , ('metric3', metric3)
          ) x(metric, val)
   ORDER  BY 1, 2 DESC$$
   )
AS ct (metric text, us int, uk int, fr int);

按字母顺序降序列出国家/地区名称(如演示文稿中所示)。 这也假定所有指标都已定义NOT NULL

如果不是这种情况之一或两者,请改用2参数形式:

添加"汇总"

即。每个指标的总计:

SELECT * FROM crosstab(
 $$SELECT x.metric, t.country_code, x.val
   FROM  (
      TABLE tbl1
      UNION ALL
      SELECT 'zzz_total', sum(metric1)::int, sum(metric2)::int, sum(metric3)::int  -- etc.
      FROM tbl1
      ) t
        , LATERAL (VALUES
            ('metric1', metric1)
          , ('metric2', metric2)
          , ('metric3', metric3)
          ) x(metric, val)
   ORDER  BY 1, 2 DESC$$
   )
AS ct (metric text, total int, us int, uk int, fr int);

'zzz_total'是一个任意标签,必须按字母顺序排序(或者您需要crosstab()的双参数形式。

如果您有批次指标列,则可能需要动态构建查询字符串。相关:

另请注意,即将推出的Postgres 9.5(目前为测试版)会引入专用的SQL clause for ROLLUP 相关: