T-SQL Лучший способ определить максимум даты (с учетом нулей) - PullRequest
2 голосов
/ 20 мая 2010

Я сравниваю две даты и пытаюсь определить максимум двух дат. Нулевая дата будет считаться менее действительной. Я использую следующую инструкцию, которая работает, но кажется очень неэффективной и неуклюжей. Есть ли лучший способ?

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; 

(Это в MS SQL 2000, FYI.)

Ответы [ 3 ]

6 голосов
/ 20 мая 2010
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 |
+------+------+------+

Почему это работает? если ни один из операндов не является нулевым, то мы получаем «нормальное» сравнение: ветвь then при c1> c2, ветвь else при c1 <= c2. </p>

В ветке "else" мы называем coalesce, но так как ее первый аргумент - ненулевое c2, мы возвращаем c2.

.

Но если любой операнд имеет значение null, тест c1 > c2 оценивается как false, и мы возвращаем coalesce( c2, c1 ).

Если нулевым операндом был c1, мы получаем c2, чего мы и хотим, потому что мы (для этого вопроса) называем null «меньше» любого ненулевого значения.

Если нулевым операндом был c2, мы получаем c1. Это нормально, потому что c1 либо не нуль, и, таким образом (для этого вопроса) "больше", чем ноль c2, или ...

Если оба операнда были нулевыми, мы получаем c1, но не имеет значения, какой получим, поскольку оба равны нулю.

Дополнительным преимуществом является то, что эта идиома работает для любых типов, для которых operator > работает, без дальнейших размышлений или подробностей.

4 голосов
/ 20 мая 2010

Самая ранняя дата, которую SQL Server может сохранить в поле даты и времени, - это 1 января 1753 года, поэтому, если вы просто считаете нулями эту дату, вы можете сделать это в одной строке:

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

Если ваше поле - smalldatetime, то минимальное значение - 1 января 1900 года, поэтому оно будет равно:

set nextearn = case when coalesce(lastoccurrence, '1900-01-01 00:00') > coalesce(lastearned, '1900-01-01 00:00') then lastoccurrence else lastearned end;
1 голос
/ 20 мая 2010

Попробуйте это:

Set nextearn = Case When IsNull(lastoccurrence, 0) > IsNull(lastearned , 0) 
               Then lastoccurrence Else lastearned  End

Все даты на сервере sql хранятся в виде двух целых чисел: opne, представляющее дату (количество дней с 1 января 1900 года), и другое, представляющее время (числосекунд [SmallDatetime] или миллисекунды [DateTime] с полуночи) ...

Два числа объединяются как Integer.DecimalFraction (DateInteger.TimePortion).Таким образом, число 0,0 представляет полночь 1 января 1900 года, 2,5 - полдень 3 января 1900 года и т. Д. *

Использование числа в выражении избавляет от необходимости разбирать строковое представление в число перед сравнением его счисло, которое представляет другую дату ...

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...