从 generate_series() 填写记录集中缺少的日期

Mr.*_*ato 9 postgresql aggregate postgresql-9.1 set-returning-functions

考虑:

with days as (select day::date
from generate_series(date '2013-01-01', date '2013-01-01' + 365, interval '1 day' day) day
) 
select 'Inspections'::text as data_label,
count(i.reporting_id) as daily_count, d.day as date_column
from days d
left join inspection i on i.close_case_date = d.day
group by d.day
order by d.day
Run Code Online (Sandbox Code Playgroud)

这将返回一个如下所示的集合:

data_label | daily_count | date_column
Inspections    1           01/01/13
Inspections    2           01/02/13
Inspections    4           01/04/13
Inspections    8           01/06/13
Run Code Online (Sandbox Code Playgroud)

请注意记录集中的 1 天和 2 天间隔。我需要生成一个用 0 填充的值的集合,如下所示:

data_label | daily_count | date_column
Inspections    1           01/01/13
Inspections    2           01/02/13
Inspections    0           01/03/13
Inspections    4           01/04/13
Inspections    0           01/05/13
Inspections    8           01/06/13
Run Code Online (Sandbox Code Playgroud)

我该怎么做?我不是一个数据库开发人员,并且是 Postgres 的新手,所以我不确定从哪里开始,也找不到关于如何实现这个目标的任何信息。

Erw*_*ter 15

这是一种误解。您问题中的查询已经返回了您的要求。我只更改了小细节:

SELECT text 'Inspections'       AS data_label
     , count(i.close_case_date) AS daily_count
     , d.day                    AS date_column
FROM  (
   SELECT generate_series(timestamp '2013-01-01'
                        , timestamp '2013-01-01' + interval '1 year - 1 day'
                        , interval  '1 day')::date
   ) d(day)
LEFT   JOIN inspection i ON i.close_case_date = d.day
GROUP  BY d.day
ORDER  BY d.day;
Run Code Online (Sandbox Code Playgroud)

关于生成一系列日期:

次要点

  • date '2013-01-01' + interval '1 year - 1 day'date '2013-01-01' + 365同时涵盖闰年要好。

  • 使用更便宜的子查询。不需要 CTE。

  • 为什么count(i.reporting_id)?要仅计算 中的行数i,请使用count(i.close_case_date)我们已经加入的 ,因此它不能为 NULL。count()只计算非空值。如果reporting_id可以为 NULL,则您冒着不计算这些行的风险。

或者,移动强制转换,这样我们就可以直接使用 set-returning 函数作为表表达式:

SELECT text 'Inspections'       AS data_label
     , count(i.close_case_date) AS daily_count
     , d.day::date              AS date_column
FROM   generate_series(timestamp '2013-01-01'
                     , timestamp '2013-01-01' + interval '1 year - 1 day'
                     , interval  '1 day') AS d(day)
LEFT   JOIN inspection i ON i.close_case_date = d.day::date
GROUP  BY d.day
ORDER  BY d.day;
Run Code Online (Sandbox Code Playgroud)