postgresql 中多种记录类型的 generate_series

Kyl*_*cot 8 postgresql

我有两个表,我想查询:pest_countspests看起来像:

CREATE TABLE pests(id,name)
AS VALUES
  (1,'Thrip'),
  (2,'Fungus Gnosts');

CREATE TABLE pest_counts(id,pest_id,date,count)
AS VALUES
  (1,1,'2015-01-01'::date,14),
  (2,2,'2015-01-02'::date,5);
Run Code Online (Sandbox Code Playgroud)

我想使用 postgres'generate_series来显示日期系列中发现的每种害虫的数量:

预期成绩

name         | date       | count
-------------+------------+-------
Thrip        | 2015-01-01 | 14
Thrip        | 2015-01-02 | 0
....
Fungus Gnats | 2015-01-01 | 0
Fungus Gnats | 2015-01-02 | 5
...
Run Code Online (Sandbox Code Playgroud)

我知道我需要类似以下的东西,但我不确定如何做剩下的事情:

SELECT date FROM generate_series('2015-01-01'::date, '2015-12-31'::date, '1 day') date
Run Code Online (Sandbox Code Playgroud)

dez*_*zso 8

我通常通过为所有可能的数据点(这里是害虫和日期)设置一个表格来解决这些问题。这可以通过 轻松实现CROSS JOIN,请参阅WITH下面的查询。

然后,作为完成步骤,我只是(外部)根据害虫 ID 和日期加入现有的测量值 - 可选择通过COALESCE().

所以,整个查询是:

WITH data_points AS (
    SELECT id, name, i::date
    FROM pests
    CROSS JOIN generate_series('2015-01-01'::date, '2015-01-05', '1 day') t(i)
) 
SELECT d.name, d.i, COALESCE(p.cnt, 0) 
FROM data_points AS d 
LEFT JOIN pest_counts AS p 
    ON d.id = p.pest_id 
    AND d.i = p.count_date;
Run Code Online (Sandbox Code Playgroud)

SQLFiddle上检查它。

注意:当表格或生成的系列很大时,在CROSS JOINCTE 内部进行可能是个坏主意。(它必须实现所有行,无论给定日期是否有数据)。在这种情况下,应该在FROM子句中做同样的事情,作为带括号的子连接而不是当前对 的引用data_points。通过这种方式,规划器可以更好地了解受影响的行以及使用索引的可能性。我在示例中使用 CTE 是因为它看起来更简洁。