Home > Software engineering >  DENSE_RANK() OVER and IFNULL()
DENSE_RANK() OVER and IFNULL()

Time:08-10

Let's say I have a table like this -

id number
1 1
2 1
3 1

I want to return the second largest number, and if there isn't, return NULL instead. In this case, since all the numbers in the table are the same, there isn't the second largest number, so it should return NULL.

These codes work -

SELECT IFNULL((
    SELECT number
    FROM (SELECT *, DENSE_RANK() OVER(ORDER BY number DESC) AS ranking
          FROM test) r
    WHERE ranking = 2), NULL) AS SecondHighestNumber; 

However, after I changed the order of the query, it doesn't work anymore -

SELECT IFNULL(number, NULL) AS SecondHighestNumber
FROM (SELECT *, DENSE_RANK() OVER(ORDER BY number DESC) AS ranking
          FROM test) r
WHERE ranking = 2; 

It returns blank instead of NULL. Why?

CodePudding user response:

Explanation

This is something of a byproduct of the way you are using subquery in your SELECT clause, and really without a FROM clause.

It is easy to see with a very simple example. We create an empty table. Then we select from it where id = 1 (no results as expected).

CREATE TABLE #foo (id int)
SELECT * FROM #foo WHERE id = 1; -- Empty results

But now if we take a left turn and turn that into a subquery in the select statement - we get a result!

CREATE TABLE #foo (id int)
SELECT (SELECT * FROM #foo WHERE id = 1) AS wtf; -- one record in results with value NULL

I'm not sure what else we could ask our sql engine to do for us - perhaps cough up an error and say I can't do this? Maybe return no results? We are telling it to select an empty result set as a value in the SELECT clause, in a query that doesn't have any FROM clause (personally I would like SQL to cough up and error and say I can't do this ... but it's not my call).

I hope someone else can explain this better, more accurately or technically - or even just give a name to this behavior. But in a nutshell there it is.

tldr;

So your first query has SELECT clause with an IFNULL function in it that uses a subquery ... and otherwise is a SELECT without a FROM. So this is a little weird but does what you want, as shown above. On the other hand, your second query is "normal" sql that selects from a table, filters the results, and lets you know it found nothing -- which might not be what you want but I think actually makes more sense ;)

Footnote: my "sql" here is T-SQL, but I believe this simple example would work the same in MySQL. And for what it's worth, I believe Oracle (back when I learned it years ago) actually would cough up errors here and say you can't have a SELECT clause with no FROM.

  • Related