如何将行翻转到新列中?
How do you flip rows into new columns?
我有一个 table 看起来像这样:
player_id | violation
---------------------
1 | A
1 | A
1 | B
2 | C
3 | D
3 | A
我想把它变成这个,用一堆新的列来表示违规类型,然后是每个玩家得到的每种违规类型的数量总和(不关心这些列叫什么;a/b/c/d 也很好用):
player_id | violation_a | violation_b | violation_c | violation_d
-----------------------------------------------------------------
1 | 2 | 1 | 0 | 0
2 | 0 | 0 | 1 | 0
3 | 1 | 0 | 0 | 1
我知道我该怎么做,但这需要大量的代码行,因为实际上有 100 多种类型的违规行为。有没有什么方法(可能是 tablefunc()
?)比拼写出我想要的 100 多个新列中的每一个以及每个列的逻辑更简洁?
在纯 SQL 中,我看不出您如何避免自己声明列。您必须在每一列中创建子选择或过滤器..
SELECT DISTINCT ON (t.player_id)
t.player_id,
count(*) FILTER (WHERE violation = 'A') AS violation_a,
count(*) FILTER (WHERE violation = 'B') AS violation_b,
count(*) FILTER (WHERE violation = 'C') AS violation_c,
count(*) FILTER (WHERE violation = 'D') AS violation_d
FROM t
GROUP BY t.player_id;
.. 或创建一个枢轴 table:
SELECT *
FROM crosstab(
'SELECT player_id, t2.violation, count(*) FILTER (WHERE t.violation = t2.violation)::INT
FROM t,(SELECT DISTINCT violation FROM t) t2
GROUP BY player_id, t2.violation'
) AS ct(player_id INT,violation_a int,violation_b int,violation_c int,violation_d int);
演示:db<>fiddle
我有一个 table 看起来像这样:
player_id | violation
---------------------
1 | A
1 | A
1 | B
2 | C
3 | D
3 | A
我想把它变成这个,用一堆新的列来表示违规类型,然后是每个玩家得到的每种违规类型的数量总和(不关心这些列叫什么;a/b/c/d 也很好用):
player_id | violation_a | violation_b | violation_c | violation_d
-----------------------------------------------------------------
1 | 2 | 1 | 0 | 0
2 | 0 | 0 | 1 | 0
3 | 1 | 0 | 0 | 1
我知道我该怎么做,但这需要大量的代码行,因为实际上有 100 多种类型的违规行为。有没有什么方法(可能是 tablefunc()
?)比拼写出我想要的 100 多个新列中的每一个以及每个列的逻辑更简洁?
在纯 SQL 中,我看不出您如何避免自己声明列。您必须在每一列中创建子选择或过滤器..
SELECT DISTINCT ON (t.player_id)
t.player_id,
count(*) FILTER (WHERE violation = 'A') AS violation_a,
count(*) FILTER (WHERE violation = 'B') AS violation_b,
count(*) FILTER (WHERE violation = 'C') AS violation_c,
count(*) FILTER (WHERE violation = 'D') AS violation_d
FROM t
GROUP BY t.player_id;
.. 或创建一个枢轴 table:
SELECT *
FROM crosstab(
'SELECT player_id, t2.violation, count(*) FILTER (WHERE t.violation = t2.violation)::INT
FROM t,(SELECT DISTINCT violation FROM t) t2
GROUP BY player_id, t2.violation'
) AS ct(player_id INT,violation_a int,violation_b int,violation_c int,violation_d int);
演示:db<>fiddle