for example i have an orders table with a classification column. i want to get the total per classification for each city in a state for certain identified cities, for specific date.
I have done the following, which works.
SELECT state.id AS state_id, state.name AS state_name, city.id AS city_id, city.name AS city_name, count(*) AS total, count(CASE WHEN o.classification = 'A' THEN 1 END) AS total_A, count(CASE WHEN o.classification = 'B' THEN 1 END) AS total_B, FROM orders AS o LEFT JOIN city ON o.city_id = city.id LEFT JOIN state ON city.state_id = state.id WHERE o.category = 'CATEGORY' AND o.city_id IN (1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16) AND (o.trn_date::date = '2020-05-07') GROUP BY state.id, state.name, city.id, city.name ORDER BY state.name, city.name;
The problem is that i don’t always get the same number (16) of cities specified in the in clause.
How can i always get 16 records even if they are all zero for some
Advertisement
Answer
You need to change your join order, move the orders
conditions to the left join
, and use filter
expressions on your count()
columns.
SELECT state.id AS state_id, state.name AS state_name, city.id AS city_id, city.name AS city_name, count(*) FILTER (WHERE o.city_id IS NOT NULL) AS total, count(*) FILTER (WHERE o.classification = 'A') AS total_A, count(*) FILTER (WHERE o.classification = 'B') AS total_B FROM state JOIN city on city.state_id = state.id LEFT JOIN orders AS o ON o.city_id = city.id AND o.category = 'CATEGORY' AND o.trn_date::date = '2020-05-07' WHERE city.id IN (1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16) GROUP BY state.id, state.name, city.id, city.name ORDER BY state.name, city.name;