正如已经评论的那样,问题中未定义数据类型的问题。
如果您可以接受所有结果列的类型为 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