Skip to content
Advertisement

Include zero counts when grouping by multiple columns and setting filters

I have a table (tbl) containing category (2 categories), impact (3 impacts), company name and date for example:

category | impact   | company | date      | number
---------+----------+---------+-----------|
Animal   | Critical | A       | 12/31/1999|1
Book     | Critical | B       | 12/31/2000|2
Animal   | Minor    | C       | 12/31/2001|3
Book     | Minor    | D       | 12/31/2002|4
Animal   | Medium   | E       | 1/1/2003  |5

I want to get the count of records for each category and impact and be able to add rows with zero count and also be able to filter by company and date.

In the example result set below, the count result is 1 for category = Animal and company = A. The rest is 0 records and only the Critical and Medium impacts appear

category | impact   | count
---------+----------+-------
Animal   | Critical |   1
Animal   | Medium   |   0

I’ve looked at the responses to similar questions by using joins however, adding a WHERE clause doesn’t include the zero records.

I also tried doing outer joins but it doesn’t produce desired output. For example

select a.impact, b.category, ISNULL(count(b.impact), 0) from tbl a
left outer join tbl b
on b.number = a.number
and (a.category = 'Animal' and a.company in ('A'))
group by a.impact, b.category

produces

impact   | category   | count
---------+------------+--------
Medium   |  NULL      | 0
Medium   | Animal     | 1
Critical |  NULL      | 0
Minor    |  NULL      | 0

but the desired output should be

category | impact   | count
---------+----------+-------
Animal   | Critical |   1
Animal   | Medium   |   0
Animal   | Minor    |   0

Any help will be appreciated. Answers to associated questions don’t have filtering so I will appreciate if someone can help with a query to produce desired output.

Advertisement

Answer

You need a master table with all the possible combinations of Categories and Impacts for this. Then Left join your table with the master and do the aggregation. Something like below

;WITH CAT
AS
(
    SELECT
        category 
        FROM Tbl
        GROUP BY category 
),
IMP
AS
(
    SELECT
        Impact 
        FROM Tbl
        GROUP BY Impact 
),MST
AS
(
    SELECT
        *
        FROM CAT
            CROSS JOIN IMP
)
SELECT  
    MST.category,
    MST.Impact,
    COUNT(T.Number)
    FROM MST
        LEFT JOIN Tbl T
            ON MST.category = T.category
                AND MST.Impact = T.Impact
                AND T.Company = 'A'
        WHERE MST.Category = 'Animal' GROUP BY MST.category,
    MST.Impact
User contributions licensed under: CC BY-SA
5 People found this is helpful
Advertisement