sql - 在 Postgres 中使用列名进行透视
问题描述
我有下表tbl
:
column1 | column2 | column 3
-----------------------------------
1 | 'value1' | 3
2 | 'value2' | 4
如何使用列名进行“旋转”以产生如下输出:
column1 | 1 | 2
column2 | 'value1' |'value2'
column3 | 3 | 4
解决方案
如前所述,问题中未定义数据类型的问题。
如果您对所有结果列都可以确定类型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;
从技术上讲,我们必须在 in 时强制执行正确的排序顺序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 列的原始示例:
db<>fiddle here
扩展到 3 行 4 列:
db<>fiddle here
推荐阅读
- python - 如何将 Django FilterSet 与 MultiSelectField 一起使用?
- node.js - 如何将此字符串 20346017621 转换为 20-34601762-1
- javascript - Ajax 不执行查询
- python - 跨不同平台的python可执行文件
- python - 从 HTML 模板上传带有分隔线的文件
- javascript - 如何解决 NODEJS 的错误消息问题
- assembly - FreeBSD 11.2 上使用 nasm 的“Hello, World”
- reactjs - 在 React Native 中使用初始索引渲染巨大列表的高性能方式
- javascript - 如何在数组中保存对象的索引?
- mysql - 如何在 MySQL 中字符串的第二个大写字母之前插入空格?