簡體   English   中英

SQL“IF”、“BEGIN”、“END”、“END IF”?

[英]SQL "IF", "BEGIN", "END", "END IF"?

根本不是 SQL 人。 有顧問編寫的以下代碼。

首先,它確保只選擇了一所小學——然后,在 BEGIN 之后,如果變量 @Term 等於 3,我們希望在該 IF 語句下執行這些操作。 這就是問題所在。 當@Term 不是 = 3 時,我們仍然想要下拉並執行 SECOND INSERT INTO @Classes 部分。 僅供參考 - 運行時 Term 為 = 3,但它沒有同時執行 INSERT - 在“IF @Term = 3”部分的末尾是否應該有一個 END IF 而不僅僅是一個普通的 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

它與 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塊等效,因為您只執行一條語句。 但是,出於同樣的原因,在類 C 語言的IF語句中不包含花括號是一個壞主意,因此始終最好使用BEGINEND

SQL 中沒有 ENDIF。

只有當 if 表達式為真時,才執行直接跟在 IF 后面的語句。

BEGIN ... END 結構與 IF 是分開的。 它將多個語句綁定在一起作為一個塊,可以將它們視為單個語句。 因此 BEGIN ... END 可以直接在 IF 之后使用,因此 BEGIN .... END 序列中的整個代碼塊將被執行或跳過。

在您的情況下,我懷疑 FROM XXXXX 之后的“(更多代碼)”是您的問題所在。

手頭上的代碼看起來是正確的。 如果您嘗試使用“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

您還可以重寫代碼以完全刪除嵌套的“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) 

如果這是 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)

如果我沒記錯的話,而且我經常不這樣做...... Transact-Sql 中沒有 END IF 支持。 BEGIN 和 END 應該完成這項工作。 你有錯誤嗎?

唯一一次插入@clases 失敗是在第一個插入語句中發生錯誤。

如果是這種情況,那么您需要決定第二個語句是否應該在第一個語句之前運行,或者您是否需要一個事務來執行回滾。

塊引用

就像 .NET 中的括號一樣

IF
  BEGIN
      do something
  END
ELSE 
  BEGIN 
      do something
  ELSE

等於

if
{
   do something
}
else
{
   do something
}

根據您對您想要做什么的描述,代碼似乎是正確的。 ENDIF 不是有效的 SQL 循環控制關鍵字。 您確定 INSERTS 實際上是在提取數據以放入 @Classes 嗎? 事實上,如果它很糟糕,它就不會運行。

您可能想要嘗試的是在其中放置一些 PRINT 語句。 在每個 INSERTS 上方放置一個 PRINT,只是輸出一些愚蠢的文本以表明該行正在執行。 如果你得到兩個輸出,那么你的 SELECT...INSERT... 是可疑的。 您也可以只執行 SELECT 來代替 PRINT(即不使用 INSERT),並准確查看正在提取的數據。

我修改了您的查詢,添加了允許它運行的附加內容,添加了一個循環來測試術語邏輯,然后最終提取了表中的值。 如果它運行正確(確實),您應該看到 1、2、3、3、4。 第一個'3'來自'if'語句,第二個來自fall-through。

DECLARE @SchoolCategoryCode CHAR(4) = 'Elem';
DECLARE @Term INT = 1;
DECLARE @Classes TABLE
(
    ClassID INT NOT NULL
);


IF @SchoolCategoryCode = 'Elem'

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

BEGIN

    /*----  added for testing ----*/
    WHILE @Term < 5
    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
            /*----  added for testing ----*/
                @Term;
            /*----------------------------*/
            --XXXXXX
            --FROM XXXX blah blah blah

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

        ---- **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
        /*----  added for testing ----*/
            @Term;
        /*----------------------------*/
        --         XXXXXXXX    
        --    FROM XXXXXX (more code) 

        SET @Term += 1;
    END;
    END;
    
    SELECT *
    FROM @Classes;
/*
    Expected results:
        ClassID
        1
        2
        3
        3
        4
*/

如果沒有表的實際定義和缺少的 select 語句,就沒有足夠的信息來確定問題的原因,但是通過我的簡單測試,邏輯可以正常工作。

坦率地說,這似乎應該在應用層,而不是數據庫層......

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM