postgresql - CROSSTAB PostgreSQL - Oracle 中 PIVOT 的替代方案

标签 postgresql crosstab postgresql-9.4

我正在将 Oracle 数据透视表的查询迁移到 PostgreSQL 交叉表。

create table(cntry numeric,week numeric,year numeric,days text,day text);
insert into x_c values(1,15,2015,'DAY1','MON');
...
insert into x_c values(1,15,2015,'DAY7','SUN');
insert into x_c values(2,15,2015,'DAY1','MON');
...
                values(4,15,2015,'DAY7','SUN');

我有 4 周的时间,表格中有 28 行。我的 Oracle 查询如下所示:

SELECT * FROM(select * from x_c)
PIVOT (MIN(DAY) FOR (DAYS) IN
   ('DAY1' AS DAY1 ,'DAY2' DAY2,'DAY3' DAY3,'DAY4' DAY4,'DAY5' DAY5,'DAY6' DAY6,'DAY7' DAY7 ));

结果:

cntry|week|year|day1|day2|day3|day4|day4|day6|day7|
---------------------------------------------------
   1 | 15 |2015| MON| TUE| WED| THU| FRI| SAT| SUN|
...
   4 | 18 |2015| MON| ...

现在我编写了一个像这样的 Postgres 交叉表查询:

select *
from crosstab('select cntry,week,year,days,min(day) as day
               from x_c
               group by cntry,week,year,days'
             ,'select distinct days from x_c order by 1'
             ) as (cntry numeric,week numeric,year numeric
                  ,day1 text,day2 text,day3 text,day4 text, day5 text,day6 text,day7 text);

我只得到一行作为输出:

  1|17|2015|MON|TUE| ...   -- only this row is coming

我哪里做错了?

最佳答案

您的原始查询中缺少

ORDER BY。手册:

In practice the SQL query should always specify ORDER BY 1,2 to ensure that the input rows are properly ordered, that is, values with the same row_name are brought together and correctly ordered within the row.

更重要的是(也更棘手),crosstab() 恰好需要 一个 row_name 列。这个密切相关的答案中的详细解释:

solution you found是在数组中嵌套多个列,然后再次取消嵌套。这是不必要的昂贵、容易出错且有限(仅适用于具有相同数据类型的列,否则您需要进行转换并可能丢失正确的排序顺序)。

相反,使用 rank()dense_rank() 生成代理 row_name 列(我的示例):

SELECT cntry, week, year, day1, day2, day3, day4, day5, day6, day7
FROM   crosstab (
  'SELECT dense_rank() OVER (ORDER BY cntry, week, year)::int AS rnk
        , cntry, week, year, days, day
   FROM   x_c
   ORDER  BY rnk, days'
 , $$SELECT unnest('{DAY1,DAY2,DAY3,DAY4,DAY5,DAY6,DAY7}'::text[])$$
   ) AS ct (rnk int, cntry int, week int, year int
          , day1 text, day2 text, day3 text, day4 text, day5 text, day6 text, day7 text)
ORDER  BY rnk;

我对列 cntryweekyear 使用数据类型 integer 因为这似乎是(更便宜的)合适的类型。您也可以像以前一样使用数字。

交叉表查询的基础知识:

关于postgresql - CROSSTAB PostgreSQL - Oracle 中 PIVOT 的替代方案,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47946648/

相关文章:

ruby - Rails 脚手架索引过滤

java - 在交叉表 jasper-report 中分割行

sql - 仅使用最小 COUNT() 转置行和列(又名枢轴)?

postgresql - 为什么 atttypmod 不同于 character_maximum_length?

sql - 递归 SELECT 查询返回任意深度的比率?

postgresql - SQL : How to merge two tables into one

python - 计算 DataFrame 中的出现次数

sql - 如何将PostgreSQL 9.4的jsonb类型转换为float

postgresql - 使用内连接更新 Postgresql

sql - Postgres SQL 状态 : 54000 when copying data to table