交叉表转置查询请求
Crosstab transpose query request
使用 Postgres 9.3.4,我得到了这个 table:
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 语句编写了它,但是它非常不守规矩而且很长,所以精通交叉表的人可以快速查询一下,这样我就可以继续了吗?
特别困难的是您的数据还没有准备好进行交叉制表。您需要 row_name、类别、值 形式的数据。您可以通过 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
查询只需要一次 table 扫描并且会更快:
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 参数形式:
- PostgreSQL Crosstab Query
添加“汇总”
即每个指标的总数:
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()
的 2 参数形式)。
如果您有 很多 个指标列,您可能需要动态构建查询字符串。相关:
- How to perform the same aggregation on every column, without listing the columns?
另请注意,即将推出的 Postgres 9.5(目前为测试版)引入了专用的 SQL clause for ROLLUP
。
相关:
使用 Postgres 9.3.4,我得到了这个 table:
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 语句编写了它,但是它非常不守规矩而且很长,所以精通交叉表的人可以快速查询一下,这样我就可以继续了吗?
特别困难的是您的数据还没有准备好进行交叉制表。您需要 row_name、类别、值 形式的数据。您可以通过 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
查询只需要一次 table 扫描并且会更快:
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 参数形式:
- PostgreSQL Crosstab Query
添加“汇总”
即每个指标的总数:
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()
的 2 参数形式)。
如果您有 很多 个指标列,您可能需要动态构建查询字符串。相关:
- How to perform the same aggregation on every column, without listing the columns?
另请注意,即将推出的 Postgres 9.5(目前为测试版)引入了专用的 SQL clause for ROLLUP
。
相关: