The following query returns the number of transactions per month. I would like the query to return 0 in the month when there were no transactions in the TV_TRANSACTION table (no records).
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)
At the moment the query returns the result
2020-02 | 1552
2020-03 | 6981
2020-04 | 16439
2020-05 | 5
How to modify a query to get something like this?:
2019-10 | 0
2019-11 | 0
2019-12 | 0
2020-01 | 0
2020-02 | 1552
2020-03 | 6981
2020-04 | 16439
2020-05 | 5
Start the joins from the CTE
and use LEFT
joins for the other tables, including all the conditions in the ON clauses and not the WHERE clause:
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)
Also I removed the ELSE
part from the CASE
expression of COUNT()
.
It has been commented already that you need to put the conditions in the join rather than in the where
clause. Also, the logic is much simpler if you start from the dates table, and then bring the additional tables with left join
s.
As far as I see, other optimizations of fixes are possible:
you can use dates rather than timestamps in the cte
filtering using half-open intervals is more efficient than using string functions (this makes these predicates SARGeable, meaning that they can take advantage of an index)
there is no need for the conditional logic in the count()
, since it matches the join conditions already
count()
takes in account 0
(it ignores null
values only)- presumably, you just want to count how many records are available in both tables for each date, so counting anything from the second left join
is enough
I renamed the cte to something that makes more sense to me
This should be (close enough to) what you want:
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
Thank you guys. I've modified the query below and it looks like it works
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)
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.