SQL "IF", "BEGIN", "END", "END IF"? - PullRequest
38 голосов
/ 01 января 2009

Не человек SQL вообще. Имейте следующий код, который написал консультант.

Сначала он проверяет, была ли выбрана только начальная школа, а затем, после BEGIN, если переменная @Term равна 3, мы хотим сделать то же самое в соответствии с этим оператором IF. Здесь проблема. Когда @Term не = 3, мы все еще хотим выпасть и выполнить часть SECOND INSERT INTO @Classes. К вашему сведению - термин = 3, когда он выполняется, но он не выполняет обе операции INSERT - должен ли быть END IF в конце этого раздела "IF @Term = 3" вместо простого END?

IF @SchoolCategoryCode = 'Elem' 

--- We now have determined we are processing an elementary school...

BEGIN

---- Only do the following if the variable @Term equals a 3 - if it does not, skip just this first part

    IF @Term = 3

    BEGIN

        INSERT INTO @Classes

        SELECT      
        XXXXXX  
        FROM XXXX blah blah blah

    END   <----(Should this be ENDIF?)

---- **always** "fall thru" to here, no matter what @Term is equal to - always do the following INSERT for all elementary schools

    INSERT INTO @Classes    
    SELECT
    XXXXXXXX    
    FROM XXXXXX (more code) 

END

Ответы [ 9 ]

43 голосов
/ 01 января 2009

Это связано с обычной формой для языка SQL. IF операторы, по определению, могут принимать только один SQL-оператор. Однако существует специальный вид операторов SQL, который может содержать несколько операторов SQL, блок BEGIN-END.

Если вы опустите блок BEGIN-END, ваш SQL будет работать нормально, но он будет выполнять только первый оператор как часть IF.

В основном это:

IF @Term = 3
    INSERT INTO @Classes
    SELECT              
        XXXXXX  
    FROM XXXX blah blah blah

эквивалентно тому же, что и в блоке BEGIN-END, потому что вы выполняете только один оператор. Тем не менее, по той же причине, по которой исключение фигурных скобок для оператора IF в C-подобном языке является плохой идеей, всегда предпочтительно использовать BEGIN и END.

23 голосов
/ 01 января 2009

В SQL нет ENDIF.

Оператор непосредственно следует за IF, если он выполняется, только если выражение if истинно.

Конструкция BEGIN ... END отделена от IF. Он связывает несколько операторов вместе как блок, который можно рассматривать как один оператор. Следовательно, BEGIN ... END может использоваться непосредственно после IF, и, таким образом, весь блок кода в последовательности BEGIN .... END будет либо выполнен, либо пропущен.

В вашем случае я подозреваю, что "(больше кода)" после FROM XXXXX - вот где ваша проблема.

9 голосов
/ 01 января 2009

С руки код выглядит правильно. Что если вы попробуете использовать Else и посмотрите, что произойдет?

IF @SchoolCategoryCode = 'Elem' 

--- We now have determined we are processing an elementary school...

BEGIN

---- Only do the following if the variable @Term equals a 3 - if it does not, skip just this first part

    IF @Term = 3
    BEGIN
        INSERT INTO @Classes

        SELECT              
            XXXXXX  
        FROM XXXX blah blah blah

        INSERT INTO @Classes    
        SELECT
        XXXXXXXX    
        FROM XXXXXX (more code) 
    END   <----(Should this be ENDIF?)
    ELSE
    BEGIN


        INSERT INTO @Classes    
        SELECT
        XXXXXXXX    
        FROM XXXXXX (more code) 
    END
END
3 голосов
/ 01 января 2009

Если это MS Sql Server, то то, что у вас должно работать нормально ... Фактически, технически вам вообще не нужен Begin & End, но в блоке begin-End есть только один оператор ... (я предполагаю, что @Classes - табличная переменная?)

If @Term = 3
   INSERT INTO @Classes
    SELECT                  XXXXXX  
     FROM XXXX blah blah blah
-- -----------------------------

 -- This next should always run, if the first code did not throw an exception... 
 INSERT INTO @Classes    
 SELECT XXXXXXXX        
 FROM XXXXXX (more code)
2 голосов
/ 01 января 2009

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

INSERT INTO @Classes    
SELECT XXXXXX      
FROM XXXX 
Where @Term = 3   

---- **always** "fall thru" to here, no matter what @Term is equal to - always do
---- the following INSERT for all elementary schools    
INSERT INTO @Classes        
SELECT    XXXXXXXX        
FROM XXXXXX (more code) 
1 голос
/ 01 января 2009

Единственное время, когда вторая вставка в @clases не должна срабатывать, это если в первом операторе вставки произошла ошибка.

Если это так, то вам нужно решить, должен ли второй оператор выполняться до первого ИЛИ, если вам нужна транзакция для выполнения отката.

1 голос
/ 01 января 2009

Если я правильно помню, и чаще, чем не я ... нет поддержки END IF в Transact-Sql. НАЧАЛО и КОНЕЦ должны делать эту работу. Вы получаете ошибки?

0 голосов
/ 01 января 2009

Честно говоря, это похоже на то, что должно быть на уровне приложений, а не на уровне базы данных ...

0 голосов
/ 01 января 2009

Исходя из вашего описания того, что вы хотите сделать, код кажется правильным, как есть. ENDIF не является допустимым ключевым словом цикла управления SQL. Вы уверены, что INSERTS фактически извлекают данные для помещения в @Classes? На самом деле, если бы это было плохо, оно просто не запустилось бы.

То, что вы, возможно, захотите попробовать, - это добавить туда несколько операторов PRINT. Поместите PRINT над каждым из INSERTS, просто выводя какой-то глупый текст, чтобы показать, что эта строка выполняется. Если вы получаете оба выхода, то ваш SELECT ... INSERT ... является подозрительным. Вы также можете просто сделать SELECT вместо ПЕЧАТИ (то есть без ВСТАВКИ) и посмотреть, какие именно данные извлекаются.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...