Postgresql - PIVOT -使用交叉表或任何其他SQL方法将行转换为列

wnrlj8wa  于 2023-03-17  发布在  PostgreSQL
关注(0)|答案(2)|浏览(136)

这是我的数据

id|col_name|value|
--+--------+-----+
 1|col1    |ABC  |
 2|col2    |DEF  |
 2|col2    |FGH  |
 2|col2    |IJK  |
 3|col3    |MNO  |
 3|col3    |PQR  |
 3|col3    |STU  |
 3|col3    |XYZ  |

预期输出为

id  Col1  Col2  col3
1    ABC   DEF  MNO
2    NULL  FGH  PQR
2    NULL  IJK  STU
2    NULL  NULL  XYZ
3    NULL  NULL  NULL
3    NULL  NULL  NULL

我尝试了如下所示的查询,但遇到了一个异常:
错误:返回和sql元组描述不兼容
这是我尝试的查询:

select 
    *
from 
    crosstab ('select id,col_name,value from hr.temp order by 1,2')
 AS final_result(id int, col1 TEXT, col2 TEXT, col3 TEXT);
ycl3bljg

ycl3bljg1#

您并不是在执行PIVOT,而是根据三列中的值的顺序(而不是某些分组标准)对它们进行排序。

CREATE TABLE sample_data (
  id integer,
  col_name varchar(10),
  value varchar(10)
);

INSERT INTO sample_data (id, col_name, value)
VALUES
  (1, 'col1', 'ABC'),
  (2, 'col2', 'DEF'),
  (2, 'col2', 'FGH'),
  (2, 'col2', 'IJK'),
  (3, 'col3', 'MNO'),
  (3, 'col3', 'PQR'),
  (3, 'col3', 'STU'),
  (3, 'col3', 'XYZ');

SELECT row_id,
       MAX(CASE WHEN col_name = 'col1' THEN value ELSE NULL END) AS col1,
       MAX(CASE WHEN col_name = 'col2' THEN value ELSE NULL END) AS col2,
       MAX(CASE WHEN col_name = 'col3' THEN value ELSE NULL END) AS col3
FROM
(
    select col_name
          ,value 
          ,ROW_NUMBER() OVER (PARTITION BY col_name ORDER BY id) as row_id
    from sample_data 
) DS
GROUP BY row_id
ORDER BY row_id;

67up9zun

67up9zun2#

当然不是crosstab()的简单情况,这似乎符合以下模式:

WITH cte AS (
   SELECT id, value, row_number() OVER (PARTITION BY id ROWS
UNBOUNDED PRECEDING) AS rn
   FROM   tbl
   )
SELECT *
FROM      (SELECT rn, value FROM cte WHERE id = 1) t1(id, col1)
FULL JOIN (SELECT rn, value FROM cte WHERE id = 2) t2(id, col2) USING (id)
FULL JOIN (SELECT rn, value FROM cte WHERE id = 3) t3(id, col3) USING (id);

fiddle
但这实际上只是一个猜测,而问题是不确定的。
行的顺序是一致的,同时也是不确定的。
使用ROWS UNBOUNDED PRECEDING时,我加入了一点分泌的酱料,使它更快。

  • 查找每个客户的前3个订单

此优化将自动运行in Postgres 16.:)

相关问题