Loading...
[-]

Aggregate functions ignore nulls

Generate a sequence of numbers with a NULL to test:

WITH seq AS
(
    SELECT num
    FROM   (
            SELECT     LEVEL num
            FROM       dual
            CONNECT BY LEVEL <= 9 + 1
            )
    UNION
    SELECT null
    FROM dual
)
SELECT * FROM seq;

Sequence with NULL

Let's try a few aggregate functions:

WITH seq AS
(
    SELECT num
    FROM   (
            SELECT     LEVEL num
            FROM       dual
            CONNECT BY LEVEL <= 9 + 1
            )
    UNION
    SELECT null
    FROM dual
)
SELECT COUNT(*), COUNT(num), SUM(num), AVG(num)
  FROM seq;

Aggregates

So we can see that COUNT(*) counts the number of rows returned, whereas COUNT, SUM and AVG of num all ignore the NULL. Having the aggregates ignore NULLs makes possible the kind of query where you are classifying and aggregating different values in a single column. I'll show you what I mean by first creating some random data which can be classified:

EXEC dbms_random.initialize(123);

WITH seq AS
(
    SELECT TRUNC(dbms_random.value(1,4)) rnd, num
    FROM   (
            SELECT     LEVEL num
            FROM       dual
            CONNECT BY LEVEL <= 9 + 1
            )
    UNION
    SELECT null, null
    FROM dual
)
SELECT * FROM seq;

Sequence to classify

Now let's say we want the average of the num column for each of the posible values 1,2,3 in the rnd column. Since aggregates ignore NULLs we can easily do this with some CASE statements where we return NULL for things that aren't interesting confident in the knowledge that all aggregate functions will ignore those values:

EXEC dbms_random.initialize(123);

WITH seq AS
(
    SELECT TRUNC(dbms_random.value(1,4)) rnd, num
    FROM   (
            SELECT     LEVEL num
            FROM       dual
            CONNECT BY LEVEL <= 9 + 1
            )
    UNION
    SELECT null, null
    FROM dual
)
SELECT AVG(CASE WHEN rnd = 1 THEN num ELSE null END) one,
       AVG(CASE WHEN rnd = 2 THEN num ELSE null END) two,
       AVG(CASE WHEN rnd = 3 THEN num ELSE null END) three
  FROM seq;

Classified and averaged

Note that the dbms_random.initialize call is made to seed the random number generator to force the same sequence for each sample. Not sure if this sequence is reliable across instances or versions. This sequence was generated on 9i.

SELECT *
  FROM product_component_version;

Oracle 9i 9.2.0.8.0 64 bit Solaris

Post a Comment

Your email is never shared. Required fields are marked *

*
*