views:

250

answers:

5

For ease of discussion, consider this basic table (Test) in Access...

ID  division  name   role
1    1        Frank  100
2    2        David  101
3    3        John   101
4    2        Mike   102
5    2        Rob    102
7    3        Dave   102
8    3        Greg   102

I want to count the users of a certain role in a division. If I do a simple count(), I get the proper 0 returned:

SELECT COUNT(ID) as ct 
FROM Test 
WHERE role >=101 and division=1;

yields

division   ct
    1       0

However, I want to include the division number in the results (for the sake of further joining, reports, etc) and it always returns null/no rows instead of the division and count of 0:

SELECT division, COUNT(ID) as ct 
FROM Test WHERE role >=101 
GROUP BY division 
HAVING division=1;

or

SELECT division, COUNT(ID) as ct 
FROM Test 
WHERE role >=101 AND division=1 
GROUP BY division;

yields

division   ct

I originally came about this because I would also like this to work if the user enters a division that is not in the table (like 4)...

SELECT division, COUNT(ID) as ct 
FROM Test 
WHERE role >=101 AND division IN (1,2,4) 
GROUP BY division;

yields

division   ct
    2       3

instead of

division   ct
    1       0
    2       3
    4       0

Is it not possible to return division along with the count if the count is 0?

+2  A: 

How about this:

SELECT division, ISNULL(ct,0) AS ct
FROM divisionTable
LEFT JOIN
(SELECT division, COUNT(ID) as ct FROM Test WHERE role >=101 GROUP BY division) CountQuery
ON divisionTable.division = CountQuery.division
WHERE divisionTable.division IN (1,2,4)
flayto
Right, LEFT JOIN on a reference table will display the results, but I was trying to avoid the JOIN. Plus, it seems weird that simply grouping my results to including the limiting division in the row no longer makes the count of 0 show up.
BikeMrown
Your WHERE clause is what eliminates the zero count results. You're filtering out anything that has role < 101 and is not in division 1,2 or 4, so how would it be able to list the division with a count of zero if that division is not part of the result set?
flayto
@BikeMrown this is normal for SQL -- you can't count null -- null is special, it does not exist, it is not 0, it is null. All hail null. Seriously tho, if you want null to act like 0, you need to have another table, or use ISNULL(), COALESCE(), is null, is not null, etc.
Hogan
@flayto I guess that is where my hang-up is. I can get the proper count of 0 and using the same WHERE clause but just adding in the division to the result set I can no longer see the 0. I see your point about there being no "instance" of "1" to fill that grouped division column.@Hogan I'm not trying to count null, I have the count of 0 properly returning in the first query, I just want to add to the result set the division that count refers to.
BikeMrown
+2  A: 

The best way to do this is create a second table that list all divisions (can be a single column) then LEFT (or right) JOIN it to your query, so you are sure it will list all divisions.

MindStalker
I believe this would normalize the data better too.
Arthur Thomas
A: 

I'm not exactly sure how to do this properly in Access, but here is an idea of making sure that there is always at least one row in the result set:

SELECT *
FROM Test 
WHERE role >=101 AND division IN (1,2,4) 
UNION
SELECT 1 as ID, 1 as division, 'Dummy' as Name, 100 as role
FROM Dual
UNION
SELECT 1 as ID, 2 as division, 'Dummy' as Name, 100 as role
FROM Dual
UNION
SELECT 1 as ID, 4 as division, 'Dummy' as Name, 100 as role
FROM Dual

(Basically, this statement adds a Dummy record for each division. Dual is a dummy Oracle Table with just one record. I'm sure that there is a more elegant way of adding the records in the union, but I hope that the idea comes across.)

Then, run you count(ID) group by division on this recordset (may be a temporary query), and subtract the dummy record from the count (so the select clause would be

SELECT division, count(ID)-1
IronGoofy
A: 

Have you tried using count(*) instead of count(ID) ?

Learning
count(*) results in the same thing
BikeMrown
A: 

This works in SQL server, so maybe...

SELECT  division, COUNT(ID) AS ct
FROM    Test
WHERE   role >= 101
GROUP BY ALL division
HAVING  division = 1 ;
Damir Sudarevic