2012-05-22 3 views
9

Извинения, если это не подходит, но на самом деле это «почему», а не «как». Не уверен, что это подходит, но не знаю лучшего места, чтобы спросить, и я не могу думать, как фраза Google, чтобы получить то, что я ищу.SQL-оценка предложений IF

IF 'hell' = 'freezing over' 
    BEGIN 
    SELECT log(0) 
    END 

Посмотрите на это заявление. Нет мира, в котором предложение IF будет истинным. Если я попытаюсь запустить его, я ожидаю, что SQL перейдет через предложение IF и переместится в конец. Вместо этого я получаю:

An invalid floating point operation occurred. 

Это странно. Поэтому я предполагаю, что это так, как это делает SQL. За исключением ...

IF 'hell' = 'freezing over' 
    BEGIN 
    SELECT 1/0 
    END 

Здесь нет никаких ошибок. Заявление в предложении IF должно по-прежнему генерировать ошибку. Может ли кто-нибудь объяснить, почему этого не происходит?

Это вызвало отладку массивного набора SQL-вычислений, в котором EXP (SUM (LOG())) используется для накопления данных в условии if. Я могу изменить код, чтобы остановить это снова, но почему он оценивает что-то в условии IF, которое не выполняется.

Cheers.

EDIT: дополнительное развлечение. Попробуй поймать? Pffft

IF 1=2 
    BEGIN 
     BEGIN TRY 
      SELECT SQRT(-1) 
     END TRY 
     BEGIN CATCH 
     END CATCH 
    END 

Non математическая:

IF 1=2 
    BEGIN 
    SELECT SUBSTRING('hello',-1,-1) 
    END 

ответ

7

Мое предположение было бы, что log(0) эффективно оценивается преждевременно из-за constant-folding тогда 1/0 нет, либо из-за его оценке мощности или более вероятно, тот факт, что установка ANSI_WARNINGS повлияет на желаемый результат деления на ноль (переполнение против НОЛЬ).

+0

Предупреждения ANSI не имеют никакого значения, но это ссылка, я думаю, мне так было нужно спасибо :) –

+0

Ваш прием. По ANSI_WARNINGS я имел в виду, что если в любое время выдается «set ansi_warnings off», вы не увидите деления на нулевую ошибку. Поскольку компилятор не может заранее знать состояние флага ANSI_WARNINGS при выполнении скомпилированного запроса, он должен игнорировать любое сложенное выражение, которое увеличивает время деления на нулевое исключение во время компиляции, поскольку оно не может предсказать желаемое поведение. (Если бы ansi_warnings гарантировалось, что всегда будет 1/0, то сбрасывается до NULL) –

2

Анализатор просто не имеет ум, чтобы следовать вашей логике IF. Рассмотрим следующий пример:

IF (1 = 0) 
BEGIN 
    CREATE TABLE #t(x INT): 
END 
ELSE 
BEGIN 
    CREATE TABLE #t(x INT): 
END 

ли вы выполнить его или даже просто разобрать его, синтаксический анализатор смотрит на все CREATE TABLE заявления в партии и определяет, что вы пытались создать таблицу дважды (первый экземпляр явно Безразлично для этого должно существовать). Результат:

Msg 2714, Level 16, State 1, Line 7
Существует уже объект с именем '#t' в базе данных.

Я действительно не знаю, есть ли у меня лучший ответ для вас, чем синтаксический анализатор не такой умный, как вы.

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

IF 'hell' = 'freezing over' 
BEGIN 
    EXEC sp_executesql N'SELECT log(0);'; 
END 

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

+0

Существует около 5 условий ЕС. В одном из них выполняется расчет данных о том, что в других условиях будут возникать ошибки. Эти примеры тривиальны, чтобы показать поведение. Это было больше похоже на IF [Данные не будут вызывать ошибки] «Do calc» END –

+0

Также интересно интересно разбираться хорошо, но не выполняется успешно –

+0

Да, парсер не всегда улавливает все типы ошибок заранее, и улавливает заранее, что никогда не будет ошибок во время выполнения. Как я уже сказал, это не самый умный. Но у него есть * много * сложных правил и алгоритмов, чтобы определить, что он позволит успешно проанализировать, а что - нет.Эти правила не задокументированы, так как @GordonLinoff объяснил, что вам просто нужно знать, какие вещи будут вызывать парсер и какие вещи он даст слайду. –

0

Очевидно, существуют некоторые выражения, которые компилятор SQL пытается оценить во время компиляции по сравнению с временем выполнения. Я предполагаю, что разделение считается не слишком дорогим, поэтому оно откладывает его на время выполнения. С другой стороны, что-то действительно сложное, как log(), дорого, и они хотят сделать это во время компиляции.

Это предположение. Это также означает, что такие различия не являются детерминированными.Вы должны выяснить, какой из них работает или не работает в определенном сценарии, - и поведение может измениться между версиями базы данных.

2

Если я пытаюсь запустить него я ожидал SQL прыгать мимо пункта IF и перейти к концу.

При запуске партии три вещи происходят

  1. Ваш SQL обрабатывается

  2. Ваш SQL скомпилирован

  3. Ваш SQL выполняется

Что такое unfo rtunate заключается в том, что ошибки компиляции и выполнения в пакете на SQL-сервере приводят к тому же сообщению «Query Completed with errors». Таким образом, позволяет использовать процедуру, где его легче увидеть разницу

Рассмотрим следующий

Create proc compiletime 
as 
SELECT log(0) 
SELECT SQRT(-1) 
SELECT SUBSTRING('hello',-1,-1) 
SELECT 1/0 

Эта процедура разбирает хорошо. Однако он не может быть скомпилирован, если мы не удалим первые SELECT, потому что у нас есть некоторые константы, которые являются недействительными в качестве параметров. Было бы неплохо, если бы SELECT 1/0 также вызывало ошибку времени компиляции вместо ошибки времени выполнения, но поскольку @Alex K указывает, что поведение основано на ANSI_WARNINGS, поэтому это не ошибка времени компиляции.

Так вот почему мы видим различия между двумя первыми. Это также объясняет, почему TRY CATCH не работает с момента ошибки времени компиляции.

Теперь почему SQL-сервер компилирует недостижимый код. Поскольку в целом, чтобы знать, что он недоступен, требуется решение проблемы с остановкой. Вы можете решить в некоторых случаях, но тогда это ...


DECLARE @x as integer 
SET @x = SomeFunction() 
If (1 = @x) 
    SomeCompiletime error 

будет иметь различное поведение, которое еще более запутанной.

if (1=0) 
    SomeCompiletime error 
Смежные вопросы