【问题标题】:Pivot with column name in Postgres在 Postgres 中使用列名进行透视
【发布时间】:2021-05-23 20:06:18
【问题描述】:

我有下表tbl:

column1 | column2  | column 3
-----------------------------------
1       | 'value1' |  3
2       | 'value2' |  4

如何对列名进行“透视”以产生如下输出:

column1 |      1   |   2
column2 | 'value1' |'value2'
column3 |      3   |   4

【问题讨论】:

  • 如果你的表有10M条记录,输出应该是什么?
  • @astentx 该表有几条不超过 10 条的记录,但有很多列。
  • 您不能在 SQL 中执行此操作。结果集中的列在不同的行上有不同的类型。 (好吧,有些事情你可以做,但这不是自然的 SQL 查询。)
  • 哦,当然,SQL 结果集中的列只能有一种数据类型,所以要进行这种转置,您需要转换为某种通用类型,如 varchar 或 JSON。但是你肯定会失去原来的类型

标签: sql postgresql pivot


【解决方案1】:

正如已经评论的那样,问题中未定义数据类型的问题。

如果您可以接受所有结果列的类型为 text(每种数据类型都可以转换为 text),则可以使用以下之一:

普通 SQL

WITH cte AS (
   SELECT nu.*
   FROM   tbl t
   , LATERAL (
      VALUES
        (1, t.column1::text)
      , (2, t.column2)
      , (3, t.column3::text)
      ) nu(rn, c)
   )
SELECT *
FROM   (TABLE cte OFFSET 0 LIMIT 3) c1
JOIN   (TABLE cte OFFSET 3 LIMIT 3) c2 USING (rn);

有用的列名也是如此:

WITH cte AS (
   SELECT nu.*
   FROM   tbl t
   , LATERAL (
      VALUES
        ('column1', t.column1::text)
      , ('column2', t.column2)
      , ('column3', t.column3::text)
      ) nu(rn, c)
   )
SELECT * FROM (
   SELECT *
   FROM   (TABLE cte OFFSET 0 LIMIT 3) c1
   JOIN   (TABLE cte OFFSET 3 LIMIT 3) c2 USING (rn)
   ) t (key, row1, row2);

适用于任何现代版本的 Postgres。
SQL 字符串必须适应行数和列数。请参阅下面的小提琴!

使用文档类型作为垫脚石

使代码更短。
对于多行多列,SQL 解决方案的性能可能会更好地扩展,因为中间派生表更小。 (线程受到限制,因为 Postgres 中的表列不能超过 ~ 1600 个。)

由于无论如何都转换为text,hstore 似乎最有效。见:

SELECT key
     , arr[1] AS row1
     , arr[2] AS row2
FROM  (
   SELECT x.key, array_agg(x.value) AS arr
   FROM   tbl t, each(hstore(t)) x
   GROUP  BY 1
   ) sub
ORDER  BY 1;

从技术上讲,我们必须在array_agg() 中强制执行正确的排序顺序,但如果没有明确的ORDER BY,这应该可以工作。绝对确定您可以添加一个:array_agg(x.value ORDER BY t.ctid) 由于缺少信息,请使用 ctid。

您可以对 (Postgres 9.3+) 中的 JSON 函数执行相同的操作。只需将each(hstore(t) 替换为json_each_text(row_to_json(t)。其余部分相同。

这些小提琴演示了如何扩展每个查询:

2 行 3 列的原始示例:
dbfiddle here

扩展到 3 行 4 列:
dbfiddle here

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2018-09-07
    • 1970-01-01
    • 1970-01-01
    • 2020-05-26
    • 1970-01-01
    • 2013-05-12
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多