返回按一列ID聚合的数据,并将数据对齐到另一列ID

时间:2016-07-17 21:16:52

标签: sql arrays postgresql crosstab

我有一个包含数百万行的大表:

CREATE TABLE mytable (
    row_id bigint,
    col_id bigint,
    value double precision,
    timestamp timestamp
);

假设:

  1. list_row = row_id的列表(如果需要,可以订购)
  2. list_col = col_id的列表(如果需要,可再次订购)
  3. 两个列表可能都非常大(可能是数十万)
  4. 上表可能有数百万条目
  5. 我如何(有效地)返回资源:

    1. 列是col_id中出现的所有list_col,其出现方式与col_idlist_col出现的顺序相同
    2. 行是row_id中存在的所有list_row(它们不需要以相同的顺序出现)
    3. 每个字段都包含给定valuerow_id的{​​{1}}个。
    4. 我们只对最近记录的任何col_id对的value感兴趣,即使用row_id:col_id)或类似的过滤器
    5. 在结果中,如果给定的MAX(timestamp坐标没有记录value,则该字段应为row_id:col_id
    6. 一个澄清的视觉例子。初始表:

      null

      变为:

      +--------+--------+-------+-----------+
      | row_id | col_id | value | timestamp |
      +========+========+=======+===========+
      |   10   |   20   |  100  | 2016-0... |
      |   10   |   21   |  200  | 2015-0... |
      |   11   |   20   |  300  | 2016-1... |
      |   11   |   22   |  400  | 2016-0... |
      +--------+--------+-------+-----------+
      

      我怀疑正确的答案是首先创建一个目标为 col_id → +-----------------+ | 20 | 21 | 22 | +=====+=====+=====+ row_id (10) | 100 | 200 | | ↓ (11) | 300 | | 400 | +-----+-----+-----+ 的临时表作为列,然后进行某种连接。我无法弄清楚如何有效地做到这一点。是否可以在不需要每个col_id的临时表的情况下执行此操作?

1 个答案:

答案 0 :(得分:1)

crosstab()适用于常规查询:

因为:

  
      
  1. 两个列表可能都非常大(可能是数十万)
  2.   

Postgres的专栏太多了。 The manual:

  

表格可以包含的列数限制。取决于   列类型,介于 250和1600 之间。但是,定义一个   在这么多列附近的任何地方的桌子都非常不寻常并经常   一个有问题的设计。

我建议改为返回数组。像(适用于任何现代Postgres版本):

SELECT row_id
     , array_agg(col_id) AS cols
     , array_agg(value)  AS vals
FROM  (
   SELECT DISTINCT ON (row_id, col_id)  --  most recent values for row_id:col_id pair 
          row_id, col_id, value
   FROM   mytable
   WHERE  row_id IN (<long list>)
   AND    col_id IN (<long list>)
   ORDER  BY row_id, col_id, timestamp DESC
   ) sub
GROUP   BY 1;

关于DISTINCT ON

返回数据的几种替代方法:

SELECT json_agg(json_build_object('col_id', col_id
                                , 'value' , value)) AS col_values1  -- requires pg 9.4+
     , json_agg(json_build_object(col_id, value))   AS col_values2  -- requires pg 9.4+
     , array_agg(ARRAY[col_id, value])              AS col_values3  -- requires pg 9.5+
     , array_agg(hstore(col_id::text, value::text)) AS col_values4  -- requires pg 8.3+
FROM  ...  -- same as above

最后一个需要额外的模块hstore