如何使用PostgreSQL(Crosstab)将值与类别列的密集表获取?
我有这个玩具示例,它使我在不同类别中分开的值稀疏。我想拥有密集的矩阵,其中所有列都单独订购。
drop table if exists temp_table;
create temp table temp_table(
rowid int
, category text
, score int
);
insert into temp_table values (0, 'cat1', 10);
insert into temp_table values (1, 'cat2', 21);
insert into temp_table values (2, 'cat3', 32);
insert into temp_table values (3, 'cat2', 23);
insert into temp_table values (4, 'cat2', 24);
insert into temp_table values (5, 'cat3', 35);
insert into temp_table values (6, 'cat1', 16);
insert into temp_table values (7, 'cat1', 17);
insert into temp_table values (8, 'cat2', 28);
insert into temp_table values (9, 'cat2', 29);
给出此临时表:
ROWID | 类别 | 分数 |
---|---|---|
0 | CAT1 | 10 |
1 | CAT2 | 21 |
2 | CAT3 | 32 |
3 | CAT2 | 23 |
4 | CAT2 | 24 |
5 | CAT3 | 35 |
6 | CAT1 | 16 |
7 CAT1 16 7 | CAT1 | 17 |
8 | CAT2 | 28 |
9 | CAT2 29 CAT2 | 29 |
,然后根据其类别将分数值订购为不同的列:
select "cat1", "cat2", "cat3"
from crosstab(
$$ select rowid, category, score from temp_table $$ -- as source_sql
, $$ select distinct category from temp_table order by category $$ -- as category_sql
) as (rowid int, "cat1" int, "cat2" int, "cat3" int)
输出:
CAT1 | CAT2 | CAT3 |
---|---|---|
10 | ||
21 | ||
32 | ||
23 | ||
24 | ||
35 | ||
16 | ||
17 | ||
28 | ||
29, |
但我希望查询的结果稠密,例如:
Cat1 | Cat2 | Cat3 |
---|---|---|
10 | 21 | 32 |
16 | 23 35 | 17 |
24 | 24 | |
28 | ||
29 |
也许不是PostgreSql的Crosstab,也许不是甚至正确的工具可以做到这一点,但这首先想到,因为它会产生接近我需要的结果的稀疏桌子。
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
这应该适用于确切的给定示例数据和预期输出。
您可以在此处测试解决方案 -
编辑:
对查询的改进以得出解决方案:
选择级别()超过(按类别订单按ROWID进行分区)作为排名,rowID,类别,从temp_table订单中得分,rowID,cate cantory asc
max()
值,对于源SQL查询中获得的每个排名。This should work for the exact given example data and expected output.
You can test the solution here - https://dbfiddle.uk/?rdbms=postgres_14&fiddle=f198e40a18a282cc0d65fa6ecdf797cb
Edit:
Improvements made to your query to arrive at the solution:
select rank() over(partition by category order by rowid) as ranking, rowid, category, score from temp_table order by rowid, category asc
max()
values of each category, for each of the rankings as obtained in the source SQL query.如果已知列的数量并且相当小,则
过滤器
可能比crosstab
更好,该选项需要扩展。If the number of columns is known and it is reasonably small,
FILTER
might be a better option thanCROSSTAB
, which requires an extension.