Многие знают и используют встроенную функцию ISNULL(X, Y), которая заменяет первый аргумент на второй в случае, если он (первый) NULL. Менее употребима обратная встроенная функция NULLIF(X, Y), которая возвращает NULL, если первый аргумент равен второму. Комбинация этих двух функций позволяет избежать использования конструкций IF-ELSE или CASE-WHEN, что делает код компактнее. Если интересно посмотреть пару примеров — добро пожаловать под кат.
Например, вот код, который выводит 10 случайных целых чисел в диапазоне от 1 до 37, и ближайшее большее или равное выведенному числу значение, кратное 6.
SELECT
Q.Src,
CASE
WHEN Q.Src % 6 = 0 THEN Q.Src
ELSE Q.Src + (6 - Q.Src % 6)
END AS NextTimes6
FROM (
SELECT TOP 10
CONVERT(INT, 1 + 37 * RAND(CHECKSUM(NEWID()))) Src
FROM SYSOBJECTS S
) Q
От CASE..WHEN можно избавиться, проделав следующий трюк — обратив в NULL результат выражения Q.Src % 6 в случае, если остаток равен 0, зная, что результат любой операции с NULL равен NULL, и восстанавливая затем обратно NULL до 0 внешней функцией ISNULL:
SELECT
Q.Src,
Q.Src + ISNULL(6 - NULLIF(Q.Src % 6, 0), 0) AS NextTimes6
FROM (
SELECT TOP 10
CONVERT(INT, 1 + 37 * RAND(CHECKSUM(NEWID()))) Src
FROM SYSOBJECTS S
) Q
Еще один пример — разделение строки на две части по пробелу (например, имени из строки Имя<пробел>Фамилия. Типичная проблема здесь при решении «в лоб» — падение функции LEFT при передаче ей аргумента -1 в качестве значения количества отрезаемых символов в случае, когда пробела в исходной строке не находится (CHARINDEX возвращает 0):
SELECT
Q.Src,
CASE
WHEN CHARINDEX(' ', Q.Src) > 0 THEN LEFT(Q.Src, CHARINDEX(' ', Q.Src) - 1)
ELSE Q.Src
END AS NameOnly
FROM (
SELECT N'Петр Иванов' AS Src
UNION ALL
SELECT N'Иван'
) Q
Превращается в:
SELECT
Q.Src,
LEFT(Q.Src, ISNULL(NULLIF(CHARINDEX(' ', Q.Src), 0) - 1, LEN(Q.Src))) AS NameOnly
FROM (
SELECT N'Петр Иванов' AS Src
UNION ALL
SELECT N'Иван'
) Q
Приятного SQL-программирования!
Автор: gleb_l