[SQL] [DB2] Возвращает 0, если нет записей - PullRequest
0 голосов
/ 25 мая 2020

Следующий запрос возвращает количество транзакций в месяц. Я хочу, чтобы запрос возвращал 0 в том месяце, когда в таблице TV_TRANSACTION не было транзакций (нет записей).

WITH
msc (num) AS
(VALUES (TIMESTAMP('2019-10-01 00:00:00.001'))
UNION ALL
SELECT num + 1 MONTH
FROM msc
WHERE num < current timestamp - 1 MONTH
)
SELECT SUBSTR(CHAR(num),1,7), 
count(case when t.STATUS = 44 and t.TRANSACTION_TYPE = 0 then 1 else 0 end) FROM TV_TRANSACTION t
join TB_INSTALLATION i on t.INSTALLATION_ID = i.INSTALLATION_ID
right join msc mc on SUBSTR(CHAR(t.REGISTRATION_DATE),1,7) = SUBSTR(CHAR(mc.num),1,7)
where i.IB24_VERSION = 2
and date(t.REGISTRATION_DATE) >= '2019-10-01'
and t.STATUS = 44
and t.TRANSACTION_TYPE = 0
and SUBSTR(CHAR(t.REGISTRATION_DATE),1,7) >= SUBSTR(CHAR(i.IB24_VERSION_UPDATE_DATE),1,7)
group by SUBSTR(CHAR(mc.num),1,7)

На данный момент запрос возвращает результат

2020-02 | 1552
2020-03 | 6981
2020-04 | 16439
2020-05 | 5

Как изменить запрос, чтобы получить что-то вроде этого?:

2019-10 | 0
2019-11 | 0
2019-12 | 0
2020-01 | 0    
2020-02 | 1552
2020-03 | 6981
2020-04 | 16439
2020-05 | 5

Ответы [ 3 ]

1 голос
/ 25 мая 2020

Уже было сказано, что вам нужно поместить условия в объединение, а не в предложение where. Кроме того, logi c намного проще, если вы начнете с таблицы дат, а затем принесете дополнительные таблицы с left join s.

Насколько я вижу, возможны другие оптимизации исправлений:

  • вы можете использовать даты, а не временные метки в cte

  • , фильтрация с использованием полуоткрытых интервалов более эффективна, чем использование строковых функций (это делает эти предикаты SARGeable, что означает, что они могут воспользоваться преимуществом индекса)

  • нет необходимости в условном logi c в count(), поскольку он уже соответствует условиям соединения

  • count() учитывает 0 (игнорирует только null значения) - предположительно, вы просто хотите подсчитать, сколько записей доступно в обеих таблицах для каждой даты, поэтому подсчета всего, начиная со второго left join достаточно

  • Я переименовал cte во что-то более понятное для меня

Это должно быть ( достаточно близко к) тому, что вы хотите:

with all_dates (dt) as
    (values (date('2019-10-01''))
    union all
    select num + 1 month from msc where num < current timestamp 
)
select 
    d.dt,
    count(i.installation_id) no_matches 
from  all_dates d
left join tv_transaction t
    on  t.registration_date >= d.dt
    and t.registration_date < d.dt + 1 day
    and t.status = 44
    and t.transaction_type = 0
left join tb_installation i 
    on  i.installation_id = t.installation_id
    and i.ib24_version = 2
    and i.ib24_version_update_date <= d.dt
group by d.dt
1 голос
/ 25 мая 2020

Начните объединения с CTE и используйте LEFT объединения для других таблиц, включая все условия в предложениях ON, а не в предложении WHERE:

WITH msc(num) AS (
  VALUES (TIMESTAMP('2019-10-01 00:00:00.001'))
  UNION ALL
  SELECT num + 1 MONTH
  FROM msc
  WHERE num < current timestamp - 1 MONTH
)
SELECT 
  SUBSTR(CHAR(num),1,7), 
  COUNT(CASE WHEN t.STATUS = 44 AND t.TRANSACTION_TYPE = 0 THEN 1 END) 
FROM msc mc
LEFT JOIN TV_TRANSACTION t 
ON    SUBSTR(CHAR(t.REGISTRATION_DATE),1,7) = SUBSTR(CHAR(mc.num),1,7)
  AND date(t.REGISTRATION_DATE) >= '2019-10-01'
  AND t.STATUS = 44
  AND t.TRANSACTION_TYPE = 0
LEFT JOIN TB_INSTALLATION i 
ON    t.INSTALLATION_ID = i.INSTALLATION_ID
  AND i.IB24_VERSION = 2
  AND SUBSTR(CHAR(t.REGISTRATION_DATE),1,7) >= SUBSTR(CHAR(i.IB24_VERSION_UPDATE_DATE),1,7)
GROUP BY SUBSTR(CHAR(mc.num),1,7)

Также я удалил ELSE часть из CASE выражения COUNT().

0 голосов
/ 25 мая 2020

Спасибо, ребята. Я изменил запрос ниже, и похоже, что он работает

WITH
msc (num) AS
(VALUES (TIMESTAMP('2018-10-01 00:00:00.001'))
UNION ALL
SELECT num + 1 MONTH
FROM msc
WHERE num < current timestamp - 1 MONTH
)
SELECT substr(char(mc.num),1,7), 
count(case when t.STATUS = 44 and t.TRANSACTION_TYPE = 0 then 1 end) FROM TV_TRANSACTION t
join TB_INSTALLATION i on t.INSTALLATION_ID = i.INSTALLATION_ID and i.IB24_VERSION = 2
right join msc mc on SUBSTR(CHAR(t.REGISTRATION_DATE),1,7) = substr(char(mc.num),1,7) and date(t.REGISTRATION_DATE) >= '2019-10-01' and t.STATUS = 44 and t.TRANSACTION_TYPE = 0
and SUBSTR(CHAR(t.REGISTRATION_DATE),1,7) >= SUBSTR(CHAR(i.IB24_VERSION_UPDATE_DATE),1,7)
group by substr(char(mc.num),1,7)
...