Question

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.

Was it helpful?

Solution

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.

OTHER TIPS

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

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;
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top