Sql Postgres:对于没有matach的行,返回0作为默认值

Sql Postgres:对于没有matach的行,返回0作为默认值,sql,postgresql,date,join,Sql,Postgresql,Date,Join,我正在尝试从我的合同表中获取所有已支付的合同,并按月进行分组。我可以得到数据,但对于没有新的付费合同的月份,我希望得到零,而不是缺少月份。我曾尝试合并并生成_系列,但似乎无法获得缺少的行 我的问题是: with months as ( select generate_series( '2019-01-01', current_date, interval '1 month' ) as series ) select date(months.se

我正在尝试从我的合同表中获取所有已支付的合同,并按月进行分组。我可以得到数据,但对于没有新的付费合同的月份,我希望得到零,而不是缺少月份。我曾尝试合并并生成_系列,但似乎无法获得缺少的行

我的问题是:

 with months as (   
       select generate_series(
        '2019-01-01', current_date, interval '1 month'   
) as series )
    select date(months.series) as day, SUM(contracts.price) from months 
left JOIN contracts on date(date_trunc('month', contracts.to)) = months.series 
where contracts.tier='paid' and contracts.trial=false and (contracts.to is not NULL)  group by day;
我希望结果如下所示:

|合同价值|月| | 20 | 01-2020| | 10 | 02-2020| | 0 | 03-2020| 我可以得到有合同的行,但不能得到零行


Postgres 10.9版

您需要将条件移至on子句:

请注意对查询的一些更改:

where子句中关于c的条件在on子句中。 日期比较使用简单的数据比较,而不是截断为月份。这有助于优化器,并使索引的使用更容易。 表别名使查询更易于编写和读取。 不需要将日期转换为日期。已经是了。 对于列名来说,to是一个错误的选择,因为它是保留的。但是,我没有改变它。
您需要将条件移至on子句:

请注意对查询的一些更改:

where子句中关于c的条件在on子句中。 日期比较使用简单的数据比较,而不是截断为月份。这有助于优化器,并使索引的使用更容易。 表别名使查询更易于编写和读取。 不需要将日期转换为日期。已经是了。 对于列名来说,to是一个错误的选择,因为它是保留的。但是,我没有改变它。 我认为你想要:

with months as (   
       select generate_series('2019-01-01', current_date, interval '1 month'   ) as series 
)
select m.series as day, coalesce(sum(c.price), 0) sum_price
from months m
left join contracts c
    on  c.to >= m.series 
    and c.to <  m.series  + interval '1' month
    and co.tier = 'paid' 
    and not c.trial
group by m.series;
即:

您希望左联接表上的条件位于联接的on子句中,而不是where子句中,否则这些条件将变为强制条件,并逐出左联接返回为空的行

可优化日期过滤器,避免使用日期函数;这使得查询变得可搜索,即数据库可以利用日期列上的索引

表别名使查询更易于读取和写入

我认为你想要:

with months as (   
       select generate_series('2019-01-01', current_date, interval '1 month'   ) as series 
)
select m.series as day, coalesce(sum(c.price), 0) sum_price
from months m
left join contracts c
    on  c.to >= m.series 
    and c.to <  m.series  + interval '1' month
    and co.tier = 'paid' 
    and not c.trial
group by m.series;
即:

您希望左联接表上的条件位于联接的on子句中,而不是where子句中,否则这些条件将变为强制条件,并逐出左联接返回为空的行

可优化日期过滤器,避免使用日期函数;这使得查询变得可搜索,即数据库可以利用日期列上的索引

表别名使查询更易于读取和写入


您的建议对上述问题有效,但如果我添加横向,我会再次遇到相同的问题:选择COALESCEcountcontracts.id,0作为试用版,转换为字符序列,“YYYY-mm”作为起始日期,从生成序列“2019-01-01”,当前日期,间隔“1个月”作为序列左键加入合同。从>=序列和合同。从。。。。。。横向从合同中选择c.id作为c,其中c.tier='gold'和c.to>=系列或c.to为空,c.account\u id=contracts.account\u id和c.trial=False作为子组,由start\u按订单由start\u按描述;您的建议对上述问题有效,但如果我添加横向,我会再次遇到相同的问题:选择COALESCEcountcontracts.id,0作为试用版,转换为字符序列,“YYYY-mm”作为起始日期,从生成序列“2019-01-01”,当前日期,间隔“1个月”作为序列左键加入合同。从>=序列和合同。从。。。。。。横向从合同中选择c.id作为c,其中c.tier='gold'和c.to>=系列或c.to为空,c.account\u id=contracts.account\u id和c.trial=False作为子组,由start\u按订单由start\u按描述;您的建议对上述问题有效,但如果我添加横向,我会再次遇到相同的问题:选择COALESCEcountcontracts.id,0作为试用版,转换为字符序列,“YYYY-mm”作为起始日期,从生成序列“2019-01-01”,当前日期,间隔“1个月”作为序列左键加入合同。从>=序列和合同。从。。。。。。横向从合同中选择c.id作为c,其中c.tier='gold'和c.to>=系列或c.to为空,c.account\u id=contracts.account\u id和c.trial=False作为子组,由start\u按订单由start\u按描述@乌默尔。我不同意你的评论。首先,你似乎在抱怨这个答案,但你接受了GMB同样的答案。第二,这个答案和你的问题都没有横向连接。也许您需要问一个新问题?您的建议解决了上述问题,但如果我添加横向,我又遇到了同样的问题:选择COALESCEcountcontracts.id,0作为试用版,转换为字符系列,“YYYY-mm”作为起始日期,从生成系列“2019-01-01”,当前日期,间隔“1个月”作为序列左连接合同。从>=序列和合同。从。。。。。。横向从合同中选择c.id作为c,其中c.tier='gold'和c.to>=series或c.to为空,c.account\u id
=contracts.account_id和c.trial=False作为子组,由start_在订单中指定,由start_在描述中指定@乌默尔。我不同意你的评论。首先,你似乎在抱怨这个答案,但你接受了GMB同样的答案。第二,这个答案和你的问题都没有横向连接。也许你需要问一个新问题?