Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

T-SQL Better way to determine max of date (accounting for nulls)

Tags:

t-sql

I am comparing two dates and trying to determine the max of the two dates. A null date would be considered less than a valid date. I am using the following case statement, which works - but feels very inefficient and clunky. Is there a better way?

update @TEMP_EARNED
set nextearn = case when lastoccurrence is null and lastearned is null then null
                   when lastoccurrence is null then lastearned
                   when lastearned is null then lastoccurrence
                   when lastoccurrence > lastearned then lastoccurrence
                   else lastearned end; 

(This is in MS SQL 2000, FYI.)

like image 832
Josh Avatar asked Jan 19 '26 00:01

Josh


2 Answers

select c1, c2, 
       case when c1 > c2 then c1 else coalesce(c2,c1) end as max 
from twocol;
+------+------+------+
| c1   | c2   | max  |
+------+------+------+
| NULL | NULL | NULL |
| NULL |    2 |    2 |
|    1 | NULL |    1 |
|    1 |    2 |    2 |
| NULL | NULL | NULL |
|    2 | NULL |    2 |
| NULL |    1 |    1 |
|    2 |    1 |    2 |
+------+------+------+

Why does this work? if neither operand is null, then we get a "normal" comparison: the "then" branch when c1 > c2, the else branch when c1 <= c2.

On the "else" branch, we call coalesce, but as its first argument is the non-null c2, we return c2.

.

But if either operand is null, the test c1 > c2 evaluates to false, and we return coalesce( c2, c1 ).

If the null operand was c1, we get c2, which is what we want because we are (for this question) calling null is "less than" any non-null value.

If the null operand was c2, we get c1. That's fine, because c1 is either not null, and thus (for this question) "greater than" the null c2, or...

If both operands were null, we get c1, but it doesn't matter which we get, as both are null.

An additional advantage is that this idiom works for any types for which operator > works, without further thought or details.

like image 177
tpdi Avatar answered Jan 21 '26 21:01

tpdi


The earliest date SQL Server can store in a datetime field is 1st Jan 1753, so if you just count nulls as that date then you can do it in a single line:

set nextearn = case when coalesce(lastoccurrence, '1753-01-01 00:00') > coalesce(lastearned, '1753-01-01 00:00') then lastoccurrence else lastearned end;

If your field is a smalldatetime then the minimum is 1st Jan 1900 so it would be:

set nextearn = case when coalesce(lastoccurrence, '1900-01-01 00:00') > coalesce(lastearned, '1900-01-01 00:00') then lastoccurrence else lastearned end;
like image 29
Dave D Avatar answered Jan 21 '26 20:01

Dave D



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!