数千列的动态枢轴

Posted

技术标签:

【中文标题】数千列的动态枢轴【英文标题】:Dynamic pivot for thousands of columns 【发布时间】:2015-07-16 14:13:35 【问题描述】:

我正在使用 pgAdmin III / PostgreSQL 9.4 来存储和处理我的数据。我当前数据的样本:

x | y
--+--
0 | 1
1 | 1
2 | 1
5 | 2
5 | 2
2 | 2
4 | 3
6 | 3
2 | 3

我希望如何格式化:

1, 2, 3 -- 列名是唯一的 y0, 5, 4 -- 第一个对应的x1, 5, 6 -- 第二个对应的x 值@ 987654330@ -- 等等

它需要是动态的,因为我有数百万行和数千个 y 的唯一值。

为此使用动态枢轴方法是否正确?我无法成功地实现这一点:

DECLARE @columns VARCHAR(8000)

SELECT @columns = COALESCE(@columns + ',[' + cast(y as varchar) + ']',
'[' + cast(y as varchar)+ ']')
FROM tableName
GROUP BY y

DECLARE @query VARCHAR(8000)

SET @query = '
SELECT x
FROM tableName
PIVOT
(
MAX(x)
FOR [y]
IN (' + @columns + ')
)
AS p'

EXECUTE(@query)

它在第一行停止并给出错误:

syntax error at or near "@"

我见过的所有动态枢轴示例都使用这个,所以我不确定我做错了什么。任何帮助表示赞赏。感谢您的宝贵时间。

**注意:以正确的顺序存储x 值很重要,因为顺序很重要。如有必要,我可以添加另一列来指示顺序。

【问题讨论】:

首先,您是否尝试打印您的@query?您可能会在那里找到有用的东西并对其进行调试。 嗨,Evaldas,我在尝试打印 @query 时遇到同样的错误:“@”或附近的语法错误 问题是代码是为 Microsoft SQL Server 编写的,并且是为 Microsoft SQL Server 编写的,因此在 Postgresql 中不起作用。不过,在 Postgresql 中也有一些方法可以做到这一点,例如这个问题所示:***.com/questions/28087948/… 也看到这个问题 - 它有更好的答案:***.com/questions/3002499/… 哦,谢谢。我对 SQL 很陌生,我尝试的来源没有指定使用的 SQL 类型。我将从另一篇文章开始工作,看看我能做什么。 【参考方案1】:

术语“第一行”假定行的自然顺序,这在数据库表中不存在。所以,是的,你需要像你怀疑的那样add another column to indicate sequential order。为此,我假设有一列 tbl_id。使用ctid 将是最后的手段。见:

Deterministic sort order for window functions

您提供的代码看起来像 MS SQL Server 代码; Postgres 的语法无效。

对于millions of rows and thousands of unique values for Y,尝试返回单个列甚至没有意义。 Postgres 有很大的限制,但还不够慷慨。 According to the source code 或the manual,绝对最大列数为1600

所以我们甚至没有讨论 SQL 的限制性特征,它要求在执行时知道列和数据类型,而不是在执行期间动态调整。您将需要两个单独的调用,就像我们在此相关问题下详细讨论的那样。

Dynamic alternative to pivot with CASE and GROUP BY

Clodoaldo 在同一问题下的另一个答案返回数组。这实际上可以是完全动态的。这也是我在这里的建议。查询其实很简单:

WITH cte AS (
   SELECT *, row_number() OVER (PARTITION BY y ORDER BY tbl_id) AS rn
   FROM   tbl
   ORDER  BY y, tbl_id
   )
SELECT text 'y' AS col, array_agg (y) AS values
FROM   cte
WHERE  rn = 1

UNION ALL
(  -- parentheses required
SELECT text 'x' || rn, array_agg (x)
FROM   cte
GROUP  BY rn
ORDER  BY rn
);

结果:

col | values
----+--------
y   | 1,2,3
x1  | 0,5,4
x2  | 1,5,6
x3  | 2,2,2

db小提琴here旧sqlfiddle

说明

CTE 为每组y 的每一行(每个x)计算一个row_number rn。我们将使用它两次,因此是 CTE。

外部查询中的第一个SELECT 生成y 值的数组。

外部查询中的第二个SELECT 按顺序生成所有x 值的数组。数组可以有不同的长度。

为什么UNION ALL 有括号?见:

Sum results of a few queries and then find top 5 in SQL

【讨论】:

以上是关于数千列的动态枢轴的主要内容,如果未能解决你的问题,请参考以下文章

MySQL 动态枢轴

动态 sql 枢轴连接

是否可以编写具有多个动态枢轴的查询?

Row_Number() 需要动态枢轴

Android围绕动态枢轴旋转视图

Oracle 查询中的动态枢轴使用情况