创建具有多个类别的Postgresql交叉表查询

问题描述 投票:0回答:1

到目前为止,我已经创建了一个查询,可以给我以下结果:

+------------+----------+-------------+-------+
|    date    | category | subcategory | count |
+------------+----------+-------------+-------+
| 2020-04-23 | One      | First       |     1 |
| 2020-04-23 | Two      | Second      |     1 |
| 2020-04-23 | Two      | First       |     3 |
| 2020-04-23 | Three    | Third       |     3 |
| 2020-04-23 | Three    | Second      |     1 |
| 2020-04-23 | Four     | Second      |     2 |
| 2020-04-23 | Five     | Third       |     3 |
| 2020-04-23 | Five     | Second      |     1 |
| 2020-04-23 | Five     | First       |     1 |
| 2020-04-23 | Six      | Third       |     1 |
| 2020-04-23 | Six      | Second      |     2 |
+------------+----------+-------------+-------+

我想将其转换为以下内容,但无法弄清楚:

+------------+----------+-------+--------+-------+
|    date    | category | First | Second | Third |
+------------+----------+-------+--------+-------+
| 2020-04-23 | One      |     1 |      0 |     0 |
| 2020-04-23 | Two      |     2 |      3 |     0 |
| 2020-04-23 | Three    |     0 |      1 |     3 |
| 2020-04-23 | Five     |     1 |      2 |     3 |
| 2020-04-23 | Six      |     0 |      2 |     1 |
+------------+----------+-------+--------+-------+

我尝试了以下操作,但是它是looks like you have to return a row, column, and value when using crosstab,所以它不起作用:

SELECT *
FROM crosstab(
    $$
        SELECT date, category, subcategory, count(*)
        -- ...
        GROUP BY 1, 2, 3
    $$
)
AS ct(date date, category text, First int, Second int, Third int);

使用交叉表时是否可以使用多个值作为行指示符,还是我必须找到其他方法?

postgresql crosstab
1个回答
0
投票

我发现了一个解决方案,尽管它并不理想:将前两个合并成一个唯一的字符,用CTE获取交叉表查询,然后拆分结果列。看起来像:

WITH crosstb AS (
    SELECT *
    FROM crosstab(
        $$
        -- Concatenate date and category columns
        SELECT date || '_' || category, subcategory, count(*)
        -- ...
        GROUP BY 1, 2
        $$,
        -- Specify data columns to ensure 0-count rows don't break it
        $$VALUES ('First'), ('Second'), ('Third')$$
    )
    AS ct(datecat text, First numeric, Second numeric, Third numeric)
)
SELECT 
    -- Split datecat column into separate again
    (regexp_split_to_array(datecat, '_'))[1]::date as Date, 
    (regexp_split_to_array(datecat, '_'))[2] as category, 
    First,
    Second,
    Third
FROM crosstb;
© www.soinside.com 2019 - 2024. All rights reserved.