Postgres - 带交叉表的部分枢轴
Postgres - partial pivot with crosstab
我正在苦苦挣扎,知道搜索答案的术语可能是我的问题,因为我无法想象这是一个边缘案例。
我在 Postgres 9.4 中有一个 table:
CREATE TABLE test (
id serial PRIMARY KEY, cust_id INTEGER,
category VARCHAR, key INTEGER, value INTEGER
);
INSERT INTO test (cust_id, category, key, value)
VALUES
(1, 'alpha', 0,300),(1, 'bravo', 0,150),(1, 'alpha', 1,300),
(1, 'bravo', 1,200),(1, 'alpha', 2,300),(1, 'bravo', 2,250),
(2, 'alpha', 0,301),(2, 'bravo', 0,151),(2, 'alpha', 1,301),
(2, 'bravo', 1,201),(2, 'alpha', 2,301),(2, 'bravo', 2,251),
(3, 'alpha', 0,302),(3, 'bravo', 0,152),(3, 'alpha', 1,302),
(3, 'bravo', 1,202),(3, 'alpha', 2,302),(3, 'bravo', 2,252);
id | cust_id | category | key | value
----+---------+----------+-----+-------
1 | 1 | alpha | 0 | 300
2 | 1 | bravo | 0 | 150
3 | 1 | alpha | 1 | 300
4 | 1 | bravo | 1 | 200
5 | 1 | alpha | 2 | 300
6 | 1 | bravo | 2 | 250
7 | 2 | alpha | 0 | 301
8 | 2 | bravo | 0 | 151
9 | 2 | alpha | 1 | 301
10 | 2 | bravo | 1 | 201
11 | 2 | alpha | 2 | 301
12 | 2 | bravo | 2 | 251
13 | 3 | alpha | 0 | 302
14 | 3 | bravo | 0 | 152
15 | 3 | alpha | 1 | 302
16 | 3 | bravo | 1 | 202
17 | 3 | alpha | 2 | 302
18 | 3 | bravo | 2 | 252
(18 rows)
我想查询如下结果:
cust_id | category | 0 | 1 | 2
---------+----------+-----+-----+-----
1 | alpha | 300 | 300 | 300
1 | bravo | 150 | 200 | 250
2 | alpha | 301 | 301 | 301
2 | bravo | 151 | 201 | 251
3 | alpha | 302 | 302 | 302
3 | bravo | 152 | 202 | 252
(6 rows)
我试过:
SELECT
*
FROM
crosstab(
'SELECT cust_id,category,key,value FROM test ORDER BY cust_id,category,key',
$$values ('0'::INT),
('1'::INT),
('2'::INT) $$
) AS ct (
"cust_id" INT, "category" TEXT, "0" INT,
"1" INT, "2" INT
);
这让我受益匪浅(缺少 bravo 类别行并为第 1、2、3 列使用 bravo 值):
cust_id | category | 0 | 1 | 2
---------+----------+-----+-------
1 | alpha | 150 | 200 | 250
2 | alpha | 151 | 201 | 251
3 | alpha | 152 | 202 | 252
(2 rows)
我通过删除 cust_id
字段并限制为单个 id 来更接近以下内容:
SELECT
*
FROM
crosstab(
'SELECT category,key,value FROM test WHERE cust_id = 1 ORDER BY category,key',
$$values ('0'::INT),
('1'::INT),
('2'::INT) $$
) AS ct (
"category" TEXT, "0" INT,
"1" INT, "2" INT
);
但这只给出了单个 cust_id
的结果,但我需要为所有客户提供此结果:
category | 0 | 1 | 2
----------+-----+-------
alpha | 300 | 300 | 300
bravo | 150 | 200 | 250
(2 rows)
https://dbfiddle.uk/?rdbms=postgres_9.5&fiddle=2c75cf9a1b18bb980ddd72953235d54e
这是一种方法:
select cust_id , category
, max(case when key = 0 then value end) "0"
, max(case when key = 1 then value end) "1"
, max(case when key = 2 then value end) "2"
from test
group by cust_id , category
order by cust_id , category
我正在苦苦挣扎,知道搜索答案的术语可能是我的问题,因为我无法想象这是一个边缘案例。
我在 Postgres 9.4 中有一个 table:
CREATE TABLE test (
id serial PRIMARY KEY, cust_id INTEGER,
category VARCHAR, key INTEGER, value INTEGER
);
INSERT INTO test (cust_id, category, key, value)
VALUES
(1, 'alpha', 0,300),(1, 'bravo', 0,150),(1, 'alpha', 1,300),
(1, 'bravo', 1,200),(1, 'alpha', 2,300),(1, 'bravo', 2,250),
(2, 'alpha', 0,301),(2, 'bravo', 0,151),(2, 'alpha', 1,301),
(2, 'bravo', 1,201),(2, 'alpha', 2,301),(2, 'bravo', 2,251),
(3, 'alpha', 0,302),(3, 'bravo', 0,152),(3, 'alpha', 1,302),
(3, 'bravo', 1,202),(3, 'alpha', 2,302),(3, 'bravo', 2,252);
id | cust_id | category | key | value
----+---------+----------+-----+-------
1 | 1 | alpha | 0 | 300
2 | 1 | bravo | 0 | 150
3 | 1 | alpha | 1 | 300
4 | 1 | bravo | 1 | 200
5 | 1 | alpha | 2 | 300
6 | 1 | bravo | 2 | 250
7 | 2 | alpha | 0 | 301
8 | 2 | bravo | 0 | 151
9 | 2 | alpha | 1 | 301
10 | 2 | bravo | 1 | 201
11 | 2 | alpha | 2 | 301
12 | 2 | bravo | 2 | 251
13 | 3 | alpha | 0 | 302
14 | 3 | bravo | 0 | 152
15 | 3 | alpha | 1 | 302
16 | 3 | bravo | 1 | 202
17 | 3 | alpha | 2 | 302
18 | 3 | bravo | 2 | 252
(18 rows)
我想查询如下结果:
cust_id | category | 0 | 1 | 2
---------+----------+-----+-----+-----
1 | alpha | 300 | 300 | 300
1 | bravo | 150 | 200 | 250
2 | alpha | 301 | 301 | 301
2 | bravo | 151 | 201 | 251
3 | alpha | 302 | 302 | 302
3 | bravo | 152 | 202 | 252
(6 rows)
我试过:
SELECT
*
FROM
crosstab(
'SELECT cust_id,category,key,value FROM test ORDER BY cust_id,category,key',
$$values ('0'::INT),
('1'::INT),
('2'::INT) $$
) AS ct (
"cust_id" INT, "category" TEXT, "0" INT,
"1" INT, "2" INT
);
这让我受益匪浅(缺少 bravo 类别行并为第 1、2、3 列使用 bravo 值):
cust_id | category | 0 | 1 | 2
---------+----------+-----+-------
1 | alpha | 150 | 200 | 250
2 | alpha | 151 | 201 | 251
3 | alpha | 152 | 202 | 252
(2 rows)
我通过删除 cust_id
字段并限制为单个 id 来更接近以下内容:
SELECT
*
FROM
crosstab(
'SELECT category,key,value FROM test WHERE cust_id = 1 ORDER BY category,key',
$$values ('0'::INT),
('1'::INT),
('2'::INT) $$
) AS ct (
"category" TEXT, "0" INT,
"1" INT, "2" INT
);
但这只给出了单个 cust_id
的结果,但我需要为所有客户提供此结果:
category | 0 | 1 | 2
----------+-----+-------
alpha | 300 | 300 | 300
bravo | 150 | 200 | 250
(2 rows)
https://dbfiddle.uk/?rdbms=postgres_9.5&fiddle=2c75cf9a1b18bb980ddd72953235d54e
这是一种方法:
select cust_id , category
, max(case when key = 0 then value end) "0"
, max(case when key = 1 then value end) "1"
, max(case when key = 2 then value end) "2"
from test
group by cust_id , category
order by cust_id , category