Reputation: 1412
I'm trying to find the devices that are stuck in a certain status, and group them by their types. I query the database for the count()
of devices in that status, and then do a couple of checks to see if those devices meet the criteria. However, it is not showing the types that do not have any count()
. I need all types to be shown, even if there is nothing to count()
.
For example, currently I have this:
TYPE COUNT(DEVICE.NAME)
TYPE1 200
TYPE2 100
TYPE3 50
I need it to come back like this:
TYPE COUNT(DEVICE.NAME)
TYPE1 200
TYPE2 100
TYPE3 50
TYPE4 0
TYPE5 0
Here's what I have so far:
SELECT device.type, count(device.name)
FROM device
LEFT OUTER JOIN (SELECT type, name
FROM device) b
ON device.name = b.name
WHERE device.changedon < (((SYSDATE - DATE '1970-01-01') * 24 * 60 * 60) - (90 * 24 * 60 * 60))
AND device.status != 6 AND device.status != 8 AND device.status != 13
GROUP BY device.type
ORDER BY count(device.name) DESC;
It was later realized that the join on table b
was unnecessary, but I will leave it in the question so that the answers still accurately reflect the question.
I have tried all types of joins on the subquery and the results are the same.
Upvotes: 0
Views: 298
Reputation: 16651
Looks like what you want can be achieved by making the whole query into a subquery and applying COALESCE to get 0 for missing results.
SELECT d0.type, COALESCE(d.cnt,0) FROM device d0
LEFT OUTER JOIN (
SELECT device.type, count(device.name) AS cnt
FROM device
LEFT OUTER JOIN (SELECT type, name
FROM device) b
ON device.name = b.name
WHERE device.changedon < (((SYSDATE - DATE '1970-01-01') * 24 * 60 * 60) - (90 * 24 * 60 * 60))
AND device.status != 6 AND device.status != 8 AND device.status != 13
GROUP BY device.type) d
ORDER BY COALESCE(d.cnt,0) DESC;
Upvotes: -1
Reputation: 1271211
If you use left outer join
, you need to use it for all the joins in the query (typically). Otherwise, you might be "undoing" the earlier join.
However, I don't think that is your only issue. The expression count(d.name)
has to return at least 1 (unless name
can be NULL
).
SELECT d.type, count(h471.id)
FROM device d INNER JOIN
(SELECT type, name
FROM device
) b
ON d.name = b.name
WHERE d.changedon < (((SYSDATE - DATE '1970-01-01') * 24 * 60 * 60) - (90 * 24 * 60 * 60)) and
d.status != 6 AND d.status != 8 AND d.status != 13
GROUP BY d.type;
When using outer joins, you also have to pay attention to the where
clause. In this case, though, you are only refering to the device
table. If the switch to left outer join
doesn't fix the problem, then the issue is in the where
clause -- it is filtering out the additional devices. If that is the case, then move the where
clause to a conditional aggregation:
SELECT d.type,
sum(case when d.changedon < (((SYSDATE - DATE '1970-01-01') * 24 * 60 * 60) - (90 * 24 * 60 * 60)) and
d.status != 6 AND d.status != 8 AND d.status != 13
then 1 else 0
end)
FROM device d LEFT OUTER JOIN
(SELECT type, name
FROM device
) b
ON d.name = b.name
GROUP BY d.type;
You might be able to move some of the conditions back to the where
clause for performance reasons.
Also, I don't get the join to table b
. It would just be multiplying the number of rows (if multiple rows in device
have the same name) or doing nothing.
Upvotes: 2
Reputation: 967
I think you need something like
SELECT type, SUM(COUNT_RESULT)
FROM (
SELECT device.type, 0 COUNT_RESULT
FROM device
UNION ALL
SELECT device.type, count(1)
FROM device, h471
WHERE device.recnum = h471.id
AND device.changedon < (((SYSDATE - DATE '1970-01-01') * 24 * 60 * 60) - (90 * 24 * 60 * 60))
AND device.status != 6 AND device.status != 8 AND device.status != 13
)
GROUP BY type
Upvotes: 2