views:

405

answers:

5

On Oracle 9i, why does the following produce the result 'abc'

select 'abc ' || (select txt from 
     (select 'xyz' as txt from dual where 1=2)) 
from dual

while this produces 'abc xyz':

select 'abc ' || (select txt from 
     (select count(*), 'xyz' as txt from dual where 1=2)) 
from dual

Why does adding count(*) to the subquery result in different behavior? Should the predicate where 1=2 preclude any results in the subquery?

+15  A: 
select count(*) from dual where 1=2

returns 0. That is, a row with the value zero.

Carl Manaster
Absolutely right ... this issue came up in a much more complex query where it was obscured by other behavior. I finally realized the mistake - the original developer really needed to use count(*) over() - the analytic function correctly returns NULL - which is what the developer really wanted in this case.
LBushkin
+4  A: 

It's returning the count of everything in the subquery, which is correctly 0. Using aggregate functions always (and correctly) behaves this way and is part of the SQL standard.

Welbog
A: 

count will always return a numeric value, 0 or a positive integer, so you will always have one row in your result set.

Note that the other aggregate functions might return NULL

Bing
A: 

Understanding how aggregate functions operate in SQL is critical to writing correct queries. When adding an aggregate function (like sum, avg, min, max, count) to a query, you are asking the database to perform a group operation on a set of results. Most aggregates, like min and max, will return null when presented with an empty set of rows to operate on. The exception to this is count() - it (correctly) returns 0 when presented with an empty set or rows.

This question arose from the analysis of a much more complex query - one with multiple subquery expressions in the select clause. As it turns out, the addition of count(*) in the select expression caused some havoc to the results - as it started returning a value where none was expected.

What the developer really wanted, was a case where count(*) would produce null. The easiest way to achieve this is through the use of analytics in Oracle. The query can be written to use the analytic count equivalent: count(*) over ()

select 'abc ' || (select txt from 
     (select count(*) over (), 'xyz' as txt from dual where 1=2)) 
from dual
LBushkin
A: 
 (select 'xyz' as txt from dual where 1=2))

This sub-query DOES NOT RETURN ANY ROWS.

 (select count(*), 'xyz' as txt from dual where 1=2))

This subquery returns 1 rows ALL THE TIME.

That is the reason of the different behaviour.