Как включить нулевые значения в MIN или MAX?
У меня есть таблица, где хранятся временные данные. таблица имеет схему, похожую на:
ID INT NOT NULL IDENTITY(1,1)
RecordID INT NOT NULL
StartDate DATE NOT NULL
EndDate DATE NULL
И я пытаюсь определить даты начала и окончания каждого идентификатора записи, поэтому минимальный StartDate и максимальный EndDate. StartDate не имеет значения NULL, поэтому мне не нужно беспокоиться об этом, но мне нужен MAX (EndDate), чтобы обозначить, что в настоящее время это работает.
Важно, чтобы я сохранял значение NULL для EndDate и рассматривал его как максимальное значение.
Самая простая попытка (ниже) не работает, подчеркивая проблему, что MIN и MAX будут игнорировать NULLS (источник: http://technet.microsoft.com/en-us/library/ms179916.aspx).
SELECT recordid, MIN(startdate), MAX(enddate) FROM tmp GROUP BY recordid
Я создал скрипт SQL с базовой настройкой.
http://sqlfiddle.com/#!3/b0a75
Как я могу свести SQL Server 2008 к моей воле, чтобы получить следующий результат из данных, приведенных в SQLFiddle?
RecordId Start End
1 2009-06-19 NULL
2 2012-05-06 NULL
3 2013-01-25 NULL
4 2004-05-06 2009-12-01
Ответы
Ответ 1
Это немного уродливо, но поскольку NULL
имеет для вас особый смысл, это самый чистый способ, который я могу сделать для этого:
SELECT recordid, MIN(startdate),
CASE WHEN MAX(CASE WHEN enddate IS NULL THEN 1 ELSE 0 END) = 0
THEN MAX(enddate)
END
FROM tmp GROUP BY recordid
То есть, если какая-либо строка имеет NULL
, мы хотим заставить это быть ответом. Если строки не содержат NULL
, мы должны вернуть MIN
(или MAX
).
Ответ 2
Эффект, который вы хотите, - это обработать NULL как самую большую возможную дату, а затем заменить его NULL по завершении:
SELECT RecordId, MIN(StartDate), NULLIF(MAX(COALESCE(EndDate,'9999-12-31')),'9999-12-31')
FROM tmp GROUP BY RecordId
В вашей игре это вернет точные результаты, которые вы укажете при любых условиях.
Ответ 3
в моем выражении -
count (enddate) подсчитывает, сколько строк, где enddates не равно нулю
count (*) подсчет количества строк
Сравнивая, вы можете легко определить, содержит ли какие-либо enddates значение null. Если они идентичны, то результатом является max (enddate). В противном случае случай будет по умолчанию возвращать null, что также является ответом. Это очень популярный способ сделать эту точную проверку.
SELECT recordid,
MIN(startdate),
case when count(enddate) = count(*) then max(enddate) end
FROM tmp
GROUP BY recordid
Ответ 4
Использовать IsNull
SELECT recordid, MIN(startdate), MAX(IsNull(enddate, Getdate()))
FROM tmp
GROUP BY recordid
Я изменил MIN во второй инструкции на MAX
Ответ 5
Предполагая, что у вас есть только одна запись с нулевым значением в столбце EndDate для данного RecordID,
что-то вроде этого должно дать вам желаемый результат:
WITH cte1 AS
(
SELECT recordid, MIN(startdate) as min_start , MAX(enddate) as max_end
FROM tmp
GROUP BY recordid
)
SELECT a.recordid, a.min_start ,
CASE
WHEN b.recordid IS NULL THEN a.max_end
END as max_end
FROM cte1 a
LEFT JOIN tmp b ON (b.recordid = a.recordid AND b.enddate IS NULL)
Ответ 6
Используйте аналитическую функцию:
select case when
max(field) keep (dense_rank first order by datfin desc nulls first) is null then 1
else 0 end as flag
from MYTABLE;
Ответ 7
Я пытаюсь использовать объединение для объединения двух запросов для форматирования желаемых результатов:
SELECT recordid, startdate, enddate FROM tmp
Where enddate is null
UNION
SELECT recordid, MIN(startdate), MAX(enddate) FROM tmp GROUP BY recordid
Но я понятия не имею, повлияет ли Союз на производительность