【问题标题】:Postgresql crosstab query with multiple "row name" columns具有多个“行名”列的 Postgresql 交叉表查询
【发布时间】:2017-09-04 21:09:37
【问题描述】:

我有一个“高瘦”事实表:

CREATE TABLE facts(
    eff_date timestamp NOT NULL,
    update_date timestamp NOT NULL,
    symbol_id int4 NOT NULL,
    data_type_id int4 NOT NULL,
    source_id char(3) NOT NULL,
    fact decimal
 /* Keys */
  CONSTRAINT fact_pk
    PRIMARY KEY (source_id, symbol_id, data_type_id, eff_date),
)

我想“透视”这个报告,所以标题看起来像这样:

eff_date, symbol_id, source_id, datatypeValue1, ... DatatypeValueN

即,我希望 eff_date、symbol_id 和 source_id 的每个唯一组合都有一行。

但是,postgresql crosstab() 函数只允许在键列上。

有什么想法吗?

【问题讨论】:

  • ...样本数据?

标签: postgresql crosstab postgresql-9.4


【解决方案1】:

crosstab() 期望其输入查询(第一个参数)中的以下列,按以下顺序:

  1. row_name
  2. (可选)extra
  3. category(匹配第二个交叉表参数中的值)
  4. value

您没有row_name。使用窗口函数 dense_rank() 添加代理 row_name

您的问题留有解释的余地​​。让我们添加示例行进行演示

INSERT INTO facts (eff_date, update_date, symbol_id, data_type_id, source_id)
VALUES
   (now(), now(), 1,  5, 'foo')
 , (now(), now(), 1,  6, 'foo')
 , (now(), now(), 1,  7, 'foo')
 , (now(), now(), 1,  6, 'bar')
 , (now(), now(), 1,  7, 'bar')
 , (now(), now(), 1, 23, 'bar')
 , (now(), now(), 1,  5, 'baz')
 , (now(), now(), 1, 23, 'baz');  -- only two rows for 'baz'

解释#1:前N个值

您想为每个不同的 (source_id, symbol_id, eff_date) 列出 data_type_id 的前 N ​​个值(如果有更多,则为最小)。

为此,还需要合成category,可以合成row_number()。生成crosstab() 输入的基本查询:

SELECT dense_rank() OVER (ORDER BY eff_date, symbol_id, source_id)::int AS row_name
     , eff_date, symbol_id, source_id                                   -- extra columns
     , row_number() OVER (PARTITION BY eff_date, symbol_id, source_id
                          ORDER BY data_type_id)::int                   AS category
     , data_type_id                                                     AS value  
FROM   facts
ORDER  BY row_name, category;

交叉表查询:

SELECT *
FROM   crosstab(
  'SELECT dense_rank() OVER (ORDER BY eff_date, symbol_id, source_id)::int AS row_name
        , eff_date, symbol_id, source_id                                   -- extra columns
        , row_number() OVER (PARTITION BY eff_date, symbol_id, source_id
                             ORDER BY data_type_id)::int                   AS category
        , data_type_id                                                     AS value  
   FROM   facts
   ORDER  BY row_name, category'
, 'VALUES (1), (2), (3)'
   ) AS (row_name int, eff_date timestamp, symbol_id int, source_id char(3)
       , datatype_1 int, datatype_2 int, datatype_3 int);

结果:

行名 |有效日期 |符号 ID | source_id |数据类型_1 |数据类型_2 |数据类型_3 --------: | :----------------| --------: | :-------- | ---------: | ---------: | ---------: 1 | 2017-04-10 ... | 1 |酒吧 | 6 | 7 | 23 2 | 2017-04-10 ... | 1 |巴兹 | 5 | 23 | 3 | 2017-04-10 ... | 1 |富 | 5 | 6 | 7

解释 #2:列名中的实际值

您希望将data_type_id 的实际值附加到列名datatypeValue1, ... DatatypeValueN。其中一项或多项:

SELECT DISTINCT data_type_id FROM facts ORDER BY 1;

5, 6, 7, 23 在示例中。那么实际显示值可以只是boolean(或冗余值?)。基本查询:

SELECT dense_rank() OVER (ORDER BY eff_date, symbol_id, source_id)::int AS row_name
     , eff_date, symbol_id, source_id                                   -- extra columns
     , data_type_id                                                     AS category
     , TRUE                                                             AS value
FROM   facts
ORDER  BY row_name, category;

交叉表查询:

SELECT *
FROM   crosstab(
  'SELECT dense_rank() OVER (ORDER BY eff_date, symbol_id, source_id)::int AS row_name
        , eff_date, symbol_id, source_id                                   -- extra columns
        , data_type_id                                                     AS category
        , TRUE                                                             AS value
   FROM   facts
   ORDER  BY row_name, category'
, 'VALUES (5), (6), (7), (23)'  -- actual values
   ) AS (row_name int, eff_date timestamp, symbol_id int, source_id char(3)
       , datatype_5 bool, datatype_6 bool, datatype_7 bool, datatype_23 bool);

结果:

有效日期 |符号 ID | source_id |数据类型_5 |数据类型_6 |数据类型_7 |数据类型_23 :----------------| --------: | :-------- | :--------- | :--------- | :--------- | :---------- 2017-04-10 ... | 1 |酒吧 | |吨 |吨 |吨 2017-04-10 ... | 1 |巴兹 |吨 | | |吨 2017-04-10 ... | 1 |富 |吨 |吨 |吨 |

dbfiddle here

相关:

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-12-28
    • 2011-03-01
    相关资源
    最近更新 更多