Postgres: вернуть ноль в качестве значения по умолчанию для строк, в которых нет метача - PullRequest
1 голос
/ 20 апреля 2020

Я пытаюсь получить все оплаченные контракты из моей таблицы контрактов и сгруппировать их по месяцам. Я могу получить данные, но за месяцы, когда нет нового платного контракта, я хочу получить ноль вместо пропущенного месяца. Я попытался coalesce и generate_series , но я не могу получить пропущенную строку.

Вот мой запрос:

 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;

Я хочу результаты будут выглядеть так:

|Contract Value| Month|
| 20           | 01-2020|
| 10           | 02-2020|
| 0            | 03-2020|

Я могу получить строки, в которых есть контракт, но не могу получить нулевую строку.

Postgres Версия 10,9

Ответы [ 2 ]

2 голосов
/ 20 апреля 2020

Я думаю, что вы хотите:

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;

То есть:

  • вам нужно условие для таблицы left join ed в предложении on в соединении, а не в предложении where, в противном случае они становятся обязательными и исключают строки, в которых left join возвращается пустым

  • , фильтр по дате можно оптимизировать, чтобы избежать использование функций даты; это делает запрос SARGeable, ie база данных может использовать индекс по столбцу даты

  • псевдонимы таблицы облегчают чтение и запись запроса

1 голос
/ 20 апреля 2020

Необходимо переместить условия в предложение on:

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

Обратите внимание на некоторые изменения в запросе:

  • Условия на c, которые были в Предложение where содержится в предложении on.
  • Для сравнения дат используется простое сравнение данных, а не усечение до месяца. Это помогает оптимизатору и упрощает использование индекса.
  • Псевдонимы таблиц облегчают написание и чтение запроса.
  • Нет необходимости преобразовывать day в дату. Это уже есть.
  • to - неправильный выбор для имени столбца, потому что оно зарезервировано. Однако я не изменил его.
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...