1

I have this query where I need to know the number of records for each state for a particular column. I need states with zero records to show up on my results. Here is my query it only shows states that have a record.

SELECT DISTINCT
    StateAbbr, count (*)
FROM
    DataWarehouse
WHERE 
    FiscalYear = 2017
    AND MaltreatmentSetCode != '999' 
    AND MaltreatmentSetCode != '' 
    AND StateAbbr IN (SELECT DISTINCT StateAbbr
                      FROM DataWarehouse
                      WHERE (NOT MaltreatmentSetCode = '999')
                        AND FiscalYear = 2017)
GROUP BY 
    StateAbbr
ORDER BY 
    StateAbbr ASC
1
  • 1
    Where can we find the list of all possible states ? Also the DISTINCT StateAbbr does not make sense in you query since you are already using GROUP BY StateAbbr Commented Nov 29, 2018 at 22:53

3 Answers 3

1

You will need to select from a 'State' table to get the list of states, then join to your count to get the totals and use a coalesce to substitute 0 when there is no data returned from the datawarehouse. Simple example below:

create table #state (state varchar(1))

create table #datawarehouse (state varchar(1), data int)


insert into #state 
    values   ('a')
            ,('b')
            ,('c')
            ,('d')

insert into #datawarehouse(state, data)
    values ('a', 1)
            ,('a',2)
            ,('a',3)
            ,('b',1)

SELECT State.State, COALESCE(DataWarehouse.c, 0)
FROM   #State state
         LEFT OUTER JOIN (  SELECT  State, Count(*) c
                            FROM    #DataWareHouse datawarehouse
                            GROUP BY State) Datawarehouse
              ON   State.State = DataWareHouse.State
Sign up to request clarification or add additional context in comments.

3 Comments

This won't work, every state without an entry will have a count of 1.
Thanks user1178830, I have corrected the answer based on your feedback.
If you count a column that is null (datawarehouse.state) instead of * ...
0

Create a list of all states, left join your data to it. Count.

SELECT allstates.StateAbbr, count (data.StateAbbr)
FROM 
  (select distinct StateAbbr from datawarehouse) allstates 
  LEFT JOIN
  DataWarehouse data
  ON 
    allstates.stateabbr = data.stateabbr and
    data.FiscalYear = 2017 and
    data.MaltreatmentSetCode NOT IN('999', '') 

GROUP BY allstates.StateAbbr
ORDER BY allstates.StateAbbr ASC

Comments

0

If all values of StateAbbr that we want to return appear in rows in DataWarehouse table, we can use conditional aggregation.

As a demonstration:

SELECT dw.StateAbbr
     , SUM(CASE WHEN dw.FiscalYear = 2017 AND dw.MaltreatmentSetCode != '999' AND dw.MaltreatmentSetCode != '' THEN 1 ELSE 0 END) AS cnt
  FROM DataWarehouse dw
 GROUP BY dw.StateAbbr
 ORDER BY dw.StateAbbr ASC

Note that for each row, the CASE expression is going to be evaluated, returning either 0 or 1, and the SUM() aggregate will add the 1s and 0s up to get us a count.

If there's values of StateAbbr that should be returned by that are not in the DateWarehouse table, then we need a rowsource for those values. (Frequently, these values are in "dimension" tables in a data mart.)

Assuming Abbr is unique in the dwstate table... if this query returns the distinct list of state abbr we need to return:

SELECT s.Abbr
  FROM dwstate s
ORDER BY s.Abbr  

Then we could do something like this:

SELECT s.Abbr  AS StateAbbr 
     , SUM(CASE WHEN dw.FiscalYear = 2017 AND dw.MaltreatmentSetCode != '999' AND dw.MaltreatmentSetCode != '' THEN 1 ELSE 0 END) AS cnt
  FROM dwstate s 
  LEFT 
  JOIN DataWarehouse dw
    ON dw.StateAbbr = s.Abbr
 GROUP BY s.Abbr
 ORDER BY s.Abbr ASC

These examples omit the bit about the subquery; it's not clear (to me) which part of the specification that part is meant to satisfy.

    SELECT DISTINCT StateAbbr
      FROM DataWarehouse
     WHERE (NOT MaltreatmentSetCode = '999' )
       AND FiscalYear = 2017

If that subquery is meant to return the set of StateAbbr that we are supposed to return, then we can use that as a rowsource in place of dwstate ...

SELECT s.Abbr  AS StateAbbr 
     , SUM(CASE WHEN dw.FiscalYear = 2017 AND dw.MaltreatmentSetCode != '999' AND dw.MaltreatmentSetCode != '' THEN 1 ELSE 0 END) AS cnt
  FROM ( -- unique list of state abbreviations 
         SELECT n.StateAbbr AS Abbr
           FROM DataWarehouse n
          WHERE (NOT n.MaltreatmentSetCode = '999' )
            AND n.FiscalYear = 2017
          GROUP BY n.StateAbbr
       ) s
  LEFT 
  JOIN DataWarehouse dw
    ON dw.StateAbbr = s.Abbr
 GROUP BY s.Abbr
 ORDER BY s.Abbr ASC

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.