我正在使用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
- 列名称是唯一的y
值
0, 5, 4
- 第一个相应的x
值
1, 5, 6
- 第二个x
值{
2, 2, 2
- 等等
它需要是动态的,因为我有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
值以正确的顺序存储非常重要。如有必要,我可以添加另一列来指示顺序。
答案 0 :(得分:1)
首先 ,当您说"第一行"时,您假设行的自然顺序,这在数据库表中不存在。所以,是的,你需要add another column to indicate sequential order
像你已经怀疑的那样。我为此目的假设了一列 tbl_id
。 - 除非你想默认这个穷人的最后(不可靠)度假胜地:ctid
下一步 ,您提供的代码看起来像MS SQL Server代码,对于Postgres完全无效。
最后 ,对于millions of rows and thousands of unique values for Y
,尝试返回单个列甚至没有意义。 Postgres有慷慨的限制,但并不是那么慷慨。引用Postgres "About":
每个表250 - 1600的最大列数取决于列类型
所以我们甚至没有机会讨论SQL的限制性特征,这要求在执行时知道列及其数据类型,而不是在执行期间动态调整。所以你需要两个单独的电话,就像我们在这个相关问题下非常详细地讨论过一样。
您还会在同一问题下找到alternative returning arrays 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}
CTE为每组rn
的每一行(每个x
)计算一个row_number y
。我们将使用它两次,因此是CTE。
外部查询中的第一个SELECT
生成y
值数组。
外部查询中的第二个SELECT
按顺序生成所有x
值数组。数组可以有不同的长度。
为什么需要UNION ALL
的括号?