如何将行翻转到新列中?

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