Pull to refresh

Comments 16

UFO just landed and posted this here
Ну вместо isnull тогда тоже case использовать? A если coalesce?

UFO just landed and posted this here
Я не вижу проблемы в isnull или coalesce
Так я тоже не вижу.
Притом они в какой-то мере есть ни что иное, как удобное сокращение того, что можно было бы спокойно сделать через case. И когда-то лично мне isnull казался непривычным и «не таким» ибо в других языковых средах тот же isnull «работал» как «are variable is null»…
с nullif — скорее что-то подобное — он непривычен.

Ну а как вариант ситуации: в триггере, где например в ветке if update() надо при различиях deleted и inserted что-то положить в некий лог (реальное изменение поля) эта конструкция вполне окажется удобнее чем if isnull(old,..)<>isnull(new,..) (или сходный case)

Ну а в теме — да, вероятно не самые очевидные и идеальные примеры, но не более. Впрочем и мой пример тоже не идеален)

nullif использую в двух случаях


  1. Оборачиваю знаменатель при делении (только если он фиксированной точности). В контексте sql, null, imho, лучше подходит для указания неопределенности, чем знаковый INF.
  2. В legacy-коде для обработки магических значений, обозначающих "любое" или "недопустимое" значение. Т.е. там, где логично использовать null, а предыдущий разработчик с ними работать не умел.
нужно втыкать и разбираться
Имхо, один раз воткнете — и разберетесь. Дальше будете просто использовать, как паттерн. В случае, например, текста процедуры, я еще могу с Вами согласиться — там можно и простой-понятный IF применить. Но когда допустимо использовать только inline (выводимые поля, inline-табличные функции, вьюхи, вычислимые колонки) — это имхо хорошая альтернатива громоздким CASE-WHEN
я, к своему стыду, не слышал про NULLIF, но на форумах по sql есть немало упоминаний, надо будет присмотреться…
в первом примере наверное еще так можно:
Q.Src + 5 - (Q.Src-1) % 6  NextTimes6

Метод гарантированного наличия разделителя, в данном случае, конечно, работать будет. В этом смысле пример со строкой, наверное, не самый удачный.

Цель же статьи — показать, что существует способ средствами T-SQL в инлайне привести исключение в неиспользуемое значение, и тут же его поймать и обработать.

При этом, на мой взгляд, способ этот достаточно прозрачный, и не требует сколько-нибудь значимых усилий на его осмысление — примерно, как XOR AX, AX вместо MOV AX, 0 для очистки регистра в ассемблере. Но у каждого — свое мнение, я не настаиваю
Я только «за» многообразие подходов и готов терпеть как неочевидные выражения, так и понятные многострочные конструкции с ветвлениями, лишь бы была практическая польза. И тезис: «1 раз напрягся, а потом много раз используешь, как готовый прием» я разделяю, в крайнем случае можно и комментарий написать. Для красоты или краткости не факт, а вот если ожидается прирост производительности, то обязательно к рассмотрению. В приведенных случаях, я так понимаю, особой разницы в скорости не стоит ожидать даже на больших объемах?
UFO just landed and posted this here
UFO just landed and posted this here
Получается аналог throw catch где null это эксепнеш. Значит переписать case when на ifnull nullif не удастся если там больше двух when. Например, case a when 1 then 10 when 2 then 20 else 30 end. Только если бы была ещё одна связка двух функции аналогов ifnull и nullif и значения, которое при операции с самим собой давала сама себя. Например, сделаем ifZETA ZETAif и значение zeta. Тогда имеем два исключения null и zeta и сможем соорудить два catch
Сама функция NULLIF безусловно необходима. Но вот примеры её использования, которые были приведены, как по мне, за гранью. Оба основаны на том, что при выполнении математических операций, где одним из операндов является NULL, мы получаем NULL — это очень усложняет восприятие. И не факт, что в других реализациях стандарта SQL оно будет работать так же.
Критикуешь — предлагай. Ок, я бы использовал COALESCE. Дополнил первый пример.

SELECT
	Q.Src,
	Q.Src + ISNULL(6 - NULLIF(Q.Src % 6, 0), 0) AS NextTimes6,
        Q.Src + (6 - COALESCE(NULLIF(Q.Src % 6, 0), 6)) as NextTimes6Coalesce
FROM (
	SELECT TOP 10 
		CONVERT(INT, 1 + 37 * RAND(CHECKSUM(NEWID()))) Src
	FROM SYSOBJECTS S
) Q;


Результат
image
Имхо, тот факт, что операции с NULL дают NULL — это основа восприятия, а не его усложнение. Стандарты емнип прописывают именно такое поведение (за исключением ранних версий MS SQL для строк, в которых NULL работал, как пустая строка при конкатенации — и это считается не ANSI-совместимым поведением), и менять его на что-то другое в N+1 версии движка БД — это невероятное поведение. На что вы замените, скажем NULL-дату?

Далее, практика показывает, что SQL-программисты, у которых работа с NULL не прописана в голове, допускают трудноуловимые, зависимые от конкретных наборов данных ошибки, которые могут не ловиться тестированием, и не проявляться в работающих системах годами.
Уж лучше тренировать мозг такими примерами и научиться грамотно работать с NULLable-параметрами и данными, чем объезжать «скользкие» места, мотивируя сложностью, неочевидностью и вероятным изменением поведения в будущем
ИМХО
IsNull лучше заменить на coalesce из стандарта (его вроде mssql поддерживает)
Сомневаюсь что оптимизатор выражениям вида IsNull(,NullIf()) очень обрадуется.
p.s. про удобство, в Oracle есть nvl2, но постоянно вылетает из головы при null второй или третий аргумент возвращает, в итоге проще смотреть на case или decode(a,null,b,c)
Sign up to leave a comment.

Articles

Change theme settings