如果PostgreSQL中没有数据,则获取零值

时间:2017-03-25 15:48:50

标签: sql postgresql left-join generate-series

我在Postgres中有一个表employee

查询:

SELECT DISTINCT month_last_date,number_of_cases,reopens,csat
FROM employee
WHERE month_last_date >=(date('2017-01-31') - interval '6 month')
AND   month_last_date <= date('2017-01-31')
AND agent_id='analyst' 
AND name='SAM';

输出:

Output I get

但如果其他月份的数据不在表中,我希望列值为 0

Required output

2 个答案:

答案 0 :(得分:2)

生成您感兴趣的所有日期,LEFT JOIN到表格,默认为0 COALESCE

SELECT DISTINCT  -- see below
       i.month_last_date
     , COALESCE(number_of_cases, 0) AS number_of_cases  -- see below
     , COALESCE(reopens, 0)         AS reopens
     , COALESCE(csat, 0)            AS csat
FROM  (
   SELECT date '2017-01-31' - i * interval '1 mon' AS month_last_date
   FROM   generate_series(0, 5) i  -- see below
   ) i
LEFT   JOIN employee e ON e.month_last_date = i.month_last_date
                      AND e.agent_id = 'analyst'  -- see below
                      AND e.name = 'SAM';

注释

如果您添加或减去1个月的interval且目标月份中不存在同一天,则Postgres默认为该月的最新现有日期。所以这可以按照需要运行,你得到每个月的最后一天:

SELECT date '2017-12-31' - i * interval '1 mon'  -- note 31
FROM   generate_series(0,11) i;

但是 没有 ,你每个月都会获得第28名:

SELECT date '2017-02-28' - i * interval '1 mon'  -- note 28
FROM   generate_series(0,11) i;

安全的选择是从下个月的第一天减去1天,例如@Oto demonstrated。相关:

以下两种优化方法可以生成一个月的一系列最后几天 - 直到并包括某个月:

1。

SELECT (timestamp '2017-01-01' - i * interval '1 month')::date - 1 AS month_last_date
FROM   generate_series(-1, 10) i;  -- generate 12 months, off-by-1

输入是 一月的第一天 - 或者使用date_trunc()从给定的datetimestamp计算:

SELECT date_trunc('month', timestamp '2017-01-17')::date AS this_mon1

interval中减去date会产生timestamp。回到date后,我们可以简单地减去integer来减去天数。

2

SELECT m::date - 1 AS month_last_date
FROM   generate_series(timestamp '2017-02-01' - interval '11 month'  -- for 12 months
                     , timestamp '2017-02-01'
                     , interval '1 mon') m;

输入是 下个月的第一天 - 或者从任何给定的日期或时间戳计算它:

SELECT date_trunc('month', timestamp '2017-01-17' + interval '1 month')::date AS next_mon1

相关:

确定您确实需要 DISTINCT 。通常,(agent_id, month_last_date)将被定义为唯一,然后移除DISTINCT ...

请务必正确使用 LEFT JOIN 。加入条件进入join子句, WHERE子句:

最后,0默认为COALESCENULL填写LEFT JOIN值。
注意 COALESCE无法区分右表中的实际NULL值和缺失行填充的NULL值。如果您的列未定义NOT NULL,则可能存在歧义。

答案 1 :(得分:1)

如我所见,您需要在特定日期之前生成过去6个月的最后几天。 (在&#34; 2017-01-31&#34;在这种情况下)。

如果我正确理解,那么你可以使用这个生成所有这些日子的查询

 SELECT (date_trunc('MONTH', mnth) + INTERVAL '1 MONTH - 1 day')::DATE 
 FROM 
 generate_series('2017-01-31'::date - interval '6 month', '2017-01-31'::date, '1 month') as mnth;

您只需要对现有查询进行LEFT JOIN此查询,就可以得到理想的结果

请注意,这将返回7条记录(天),而不是6条。