Я использую функцию T-SQL, COALESCE
где первый аргумент не будет нулевым в 95% случаев, когда он запускается. Если первый аргумент NULL
, второй аргумент довольно длительный процесс:
SELECT COALESCE(c.FirstName
,(SELECT TOP 1 b.FirstName
FROM TableA a
JOIN TableB b ON .....)
)
Если, например, c.FirstName = 'John'
SQL Server все еще будет выполнять подзапрос?
Я знаю с помощью IIF()
функции VB.NET , если второй аргумент равен True, код все равно читает третий аргумент (даже если он не будет использоваться).
источник
CASE
всегда оценивает слева направо и всегда короткие замыкания ).SELECT COALESCE((SELECT CASE WHEN RAND() <= 0.5 THEN 1 END), 1);
- повторить несколько раз. Вы получитеNULL
иногда. Попробуйте еще раз сISNULL
- вы никогда не получитеNULL
...Как насчет этого - как мне сообщил Ицик Бен-Ган, которому об этом рассказал Хайме Лафарг ?
Результат:
Конечно, существуют тривиальные обходные пути, но суть в том, что
CASE
не всегда гарантируется оценка / короткое замыкание слева направо. Я сообщил об ошибке здесь, и она была закрыта как «по замыслу». Впоследствии Пол Уайт подал этот элемент подключения , и он был закрыт как исправленный. Не потому, что это было исправлено само по себе, а потому, что они обновили Books Online с более точным описанием сценария, в котором агрегаты могут изменять порядок оценкиCASE
выражения. Я недавно написал больше об этом здесь .РЕДАКТИРОВАТЬ только приложение, хотя я согласен, что это крайние случаи, что большую часть времени вы можете полагаться на оценку слева-направо и короткие замыкания, и что это ошибки, которые противоречат документации и, вероятно, в конечном итоге будут исправлены ( это не определенно - посмотрите последующий разговор в блоге Барта Дункана, чтобы понять, почему), я должен не согласиться, когда люди говорят, что что-то всегда верно, даже если есть один крайний случай, который опровергает это. Если Ицик и другие могут найти такие одиночные ошибки, как это, то, по крайней мере, существует вероятность того, что есть и другие ошибки. А поскольку мы не знаем остальной части запроса ОП, мы не можем с уверенностью сказать, что он будет полагаться на это короткое замыкание, но в конечном итоге его укусит. Поэтому для меня более безопасный ответ:
Хотя обычно вы можете рассчитывать на
CASE
оценку слева направо и на наличие короткого замыкания, как описано в документации, неверно говорить, что вы всегда можете это сделать. На этой странице есть два продемонстрированных случая, где это не так, и ни одна ошибка не была исправлена ни в одной общедоступной версии SQL Server.EDIT - это еще один случай (мне нужно прекратить это делать), когда
CASE
выражение оценивается не в том порядке, в котором вы ожидаете, даже если не используются никакие агрегаты.источник
CASE
которая была незаметно исправленаМое мнение об этом заключается в том, что документация достаточно ясно показывает, что намерение состоит в том, что CASE должен закорачиваться. Как упоминает Аарон, было несколько случаев (ха!), Где было показано, что это не всегда верно.
До сих пор все они были признаны ошибками и исправлены - хотя не обязательно в версии SQL Server, которую вы можете купить и исправить сегодня (ошибка постоянного сворачивания еще не дошла до накопительного обновления AFAIK). Новейшая потенциальная ошибка - первоначально сообщенная Ициком Бен-Ганом - еще не исследована (либо Аарон, либо я добавлю ее в ближайшее время).
Относительно исходного вопроса, есть другие проблемы с CASE (и, следовательно, COALESCE), где используются побочные функции или подзапросы. Рассмотреть возможность:
Форма COALESCE часто возвращает NULL, более подробную информацию можно найти по адресу https://connect.microsoft.com/SQLServer/feedback/details/546437/coalesce-subquery-1-may-return-null.
Продемонстрированные проблемы с преобразованиями оптимизатора и отслеживанием общего выражения означают, что невозможно гарантировать, что CASE будет иметь короткое замыкание при любых обстоятельствах. Я могу представить себе случаи, когда было бы невозможно даже предсказать поведение путем проверки выходных данных плана публичного шоу, хотя у меня сегодня нет на это информации.
Таким образом, я думаю, что вы можете быть достаточно уверены в том, что CASE в целом будет иметь короткое замыкание (особенно если достаточно квалифицированный специалист проверяет план выполнения, и этот план выполнения «исполняется» с помощью руководства или подсказок плана), но если вам нужно абсолютная гарантия, вы должны написать SQL, который вообще не содержит выражения.
Полагаю, не совсем удовлетворительное положение дел.
источник
Я сталкивался с другим случаем, когда
CASE
/COALESCE
не замыкается. Следующий TVF вызовет нарушение PK, если передан1
в качестве параметра.Если вызывается следующим образом
Или как
Оба дают результат
показывая, что
SELECT
(или, по крайней мере, заполнение табличной переменной) все еще выполняется и выдает ошибку, даже если эта ветвь оператора никогда не должна быть достигнута. План дляCOALESCE
версии ниже.Это переписывание запроса, кажется, чтобы избежать проблемы
Который дает план
источник
Другой пример
Запрос
Показывает не читает против
T2
вообще.Поиск
T2
выполняется по предикату, и оператор никогда не выполняется. НоЕсть ли шоу , которое
T2
читается. Несмотря на то, что ценность отT2
никогда не нужна.Конечно, это не удивительно, но я подумал, что стоит добавить в репозиторий контрпримеров хотя бы потому, что это поднимает вопрос о том, что означает короткое замыкание в декларативном языке на основе множеств.
источник
Я просто хотел упомянуть стратегию, которую вы, возможно, не рассматривали. Это может быть не совпадение здесь, но иногда бывает полезно. Посмотрите, дает ли эта модификация лучшую производительность:
Другой способ сделать это может быть следующим (в основном эквивалентно, но позволяет вам при необходимости получить доступ к большему количеству столбцов из другого запроса):
По сути, это метод «жесткого» объединения таблиц, но включающий условие, когда нужно присоединять любые строки. По моему опыту, это иногда помогало в выполнении планов.
источник
Нет, не будет. Это будет работать только тогда, когдаc.FirstName
естьNULL
.Тем не менее, вы должны попробовать это сами. Эксперимент. Вы сказали, что ваш подзапрос длинный. Benchmark. Сделайте свои собственные выводы по этому вопросу.@ Аарон ответ на выполняемый подзапрос является более полным.
Тем не менее, я все еще думаю, что вы должны переработать свой запрос и использовать
LEFT JOIN
. В большинстве случаев подзапросы можно удалить, переработав запрос для использованияLEFT JOIN
s.Проблема с использованием подзапросов заключается в том, что ваш общий оператор будет выполняться медленнее, потому что подзапрос выполняется для каждой строки в наборе результатов основного запроса.
источник
В действующем стандарте говорится, что все предложения WHEN (а также предложение ELSE) должны быть проанализированы для определения типа данных выражения в целом. Я действительно должен был бы получить некоторые из моих старых заметок, чтобы определить, как обрабатывается ошибка. Но 1/0 использует целые числа, поэтому я предполагаю, что пока это ошибка. Это ошибка с целочисленным типом данных. Когда в списке слияния есть только нули, определить тип данных немного сложнее, и это еще одна проблема.
источник