簡體   English   中英

SQL Server從表變量更新

[英]SQL Server Updating from a table variable

最終編輯-解決-下面的解決方案

我不敢相信我不知道這一點,但是顯然問題在於表變量和真實表都具有相同的名稱:@CHECKERS和dbo.CHECKERS。 觸發因素顯然使兩者混淆。 我是通過更改觸發器中插入和更新操作的順序來發現這一點的,以便在對表變量進行更新之后,才可以將實際表插入到表中。 突然,更新開始順利通過。

當然,我只創建了dbo.CHECKERS來調試@CHECKERS,因此顯然存在一些最初的問題,這開始了所有這一切。 但是無論如何,問題都已解決,觸發器也可以正常工作。 我將其發布在下面,因此,如果您願意,可以隨時提供任何反饋。 我不是專家(顯然),並且總是很高興收到建設性的反饋。

感謝大家的幫助和評論。 我希望這篇文章可以幫助某人避免頭痛...

查詢-解決方案

ALTER TRIGGER CatchChange ON [dbo].[Orders]

-- Last Updated : 07 Oct 2014

AFTER UPDATE
NOT FOR REPLICATION
-- Trigger not fired by agent updates
AS
BEGIN

    IF UPDATE(UpdateRecordDate)
    -- Trigger fired only by user updates that include a timestamp.
    -- Does **NOT** fire from primary stored procedure (dictated by UpdateRecordDate).
    BEGIN

        -- Table variable for storing **multi-row updates**
        -- Using scalar variables will not work! Look it up.
        DECLARE @CHECKERS AS TABLE 
        (   OrderNum INT,
            Old_DCB INT,
            New_DCB INT,
            Old_MC INT,
            New_MC INT,
            Old_P2 NUMERIC(28,3),
            New_P2 NUMERIC(28,3),
            Old_PQ NUMERIC(28,3),
            New_PQ NUMERIC(28,3),
            Old_QT NUMERIC(28,3),
            New_QT NUMERIC(28,3)
        )

        -- Old & new values populated to table variable.
        -- We can add a table in the same format as the variable &
        -- then check what values were passed, if necessary.
        -- The INSERT for this scenario is commented out at the end.
        INSERT INTO @CHECKERS
        SELECT  I.OrderNo,
                D.DriverCB,
                I.DriverCB,
                D.MCode,
                I.MCode,
                D.Price2,
                I.Price2,
                D.PriceQuantity2,
                I.PriceQuantity2,
                D.Quantity1,
                I.Quantity1
        FROM Inserted I
        JOIN Deleted D ON I.Orderno = D.OrderNo
        -- These checks are crucial, as they cut down on reiteration.
        -- Without them, the program would fire the trigger redundantly.
        -- Here we check for changes to the relevant values &
        -- ensure that the update was a new one, not a repetitive one.
        WHERE I.OrderKind = 0
        AND isnull(D.UpdateRecordDate,convert(DATETIME,0)) <> isnull(I.UpdateRecordDate,convert(DATETIME,0))
        AND (D.DriverCB <> I.DriverCB
            OR D.MCode <> I.MCode
            OR D.Price2 <> I.Price2
            OR D.PriceQuantity2 <> I.PriceQuantity2
            OR D.Price3 <> I.Price3
            OR D.PriceQuantity3 <> I.PriceQuantity3
            OR D.Quantity1 <> I.Quantity1)

        -- Case conditions are preferable in this instance to IF conditions.
        -- All relevant values are checked here against dictating conditions &
        -- updated accordingly.
        UPDATE O
        SET     
        O.DriverCB =        CASE
                            WHEN C.New_DCB = 0
                            THEN NULL
                            ELSE O.DriverCB
                            END,
                            <...>,
        O.Quantity4 =       CASE 
                            WHEN C.New_QT > 0
                            THEN O.Quantity1
                            ELSE O.Quantity4
                            END 
        FROM Orders O
        INNER JOIN @CHECKERS C ON O.OrderNo = C.OrderNum

        -- This is the INSERT which populates the debug table, if you want.
        -- Naturally, the name here must match the name of the created table!
        -- And yes, DD, you need to create the ACTUAL TABLE outside of this trigger. :)
/*      INSERT INTO CheckMe
        SELECT  C.ID,
        C.OrderNum,
        C.Old_DriverCodeBizua,
        C.New_DriverCodeBizua,
        C.Old_MaslulCode1,
        C.New_MaslulCode1,
        C.Old_Price2,
        C.New_Price2,
        C.Old_PriceQuntity2,
        C.New_PriceQuntity2,
        C.Old_Quntity,
        C.New_Quntity
        FROM @CHECKERS C    */
    END
END
GO

結束查詢-解決方案

--------開始原始帖子--------

我有一個客戶,需要我修飾一堆執行各種功能的舊觸發器。 通常,我不贊成這樣做,並認為應該更新其程序-但無論如何。

存在三個觸發器,我只需要將它們組合為一個觸發器即可,該觸發器工作起來會更平穩一些,並具有更多條件。 (目前,由於完全沒有條件,觸發器會在每次操作時運行,這很難觀察。)

簡而言之,我創建了一個新的觸發器,在其中聲明一個表變量(下面的查詢)。 我這樣做是為了讓自己直接控制列名,而不是簡單地使用SELECT X INTO #temp。 此后,我嘗試使用CASE檢查來更新主表中的各個字段,具體取決於表變量中記錄的更改。

問題在於更新不執行任何操作。 我沒有收到任何錯誤,但是主表中的值保持不變。 為了確保表變量正在獲取值並且可以使用它們,我向測試數據庫添加了一個新表,並且在每次觸發時,我將表變量中當前包含的值插入到新表中,如下所示:

        DECLARE @CHECKERS AS TABLE
        (   OrderNum INT,
            Old_DCB INT,
            New_DCB INT,
            Old_MC INT,
            New_MC INT,
            Old_QT NUMERIC(28,3),
            New_QT NUMERIC(28,3)
        )

        INSERT INTO @CHECKERS
        SELECT  I.OrderNo,
                D.DriverCB,
                I.DriverCB,
                D.MCode,
                I.MCode,
                D.Quantity,
                I.Quantity
        FROM Inserted I
        JOIN Deleted D ON I.OrderNo = D.OrderNo
        WHERE I.OrderKind = 0
        AND (D.DriverCB <> I.DriverCB
            OR D.MCode1 <> I.MCode1
            OR D.Quantity <> I.Quantity)

        INSERT INTO CHECKERS
        SELECT  OrderNum,
            Old_DCB,
            New_DCB,
            Old_MC,
            New_MC,
            Old_QT,
            New_QT
        FROM @CHECKERS
        -- An actual table created to check functionality
        -- Works up until this point

        UPDATE Orders
        SET Quantity2 = CASE 
                WHEN New_QT > 0 THEN New_QT
                ELSE Quantity2
                END
        FROM @CHECKERS C
        WHERE OrderNo = C.OrderNum

自然,實際觸發器中還有許多更新,但是您明白了。

有什么想法為什么無法更新訂單? 可能是一些小巧,愚蠢且令人尷尬的東西-但我還是說一遍;)謝謝。

--------結束原始帖子--------

-編輯:

我也嘗試過這樣編寫更新:

        UPDATE O
        SET Quantity2 = CASE 
                WHEN C.New_QT > 0 THEN C.New_QT
                ELSE Quantity2
                END
        FROM @CHECKERS C
        INNER JOIN Orders O on O.OrderNo = C.OrderNum

這種方法給出了相同的結果:沒有錯誤消息(或其他任何消息),也沒有更新...

-第二次編輯:

如果我使用實際的表CHECKERS而不是表變量@CHECKERS,則更新通過:

            UPDATE O
            SET Quantity2 = CASE 
                    WHEN C.New_QT > 0 THEN C.New_QT
                    ELSE Quantity2
                    END
            FROM CHECKERS C -- Actual table, not a table variable!
            INNER JOIN Orders O on O.OrderNo = C.OrderNum

無論JOIN中是否存在訂單,這也都有效:

UPDATE Orders
            SET Quantity2 = CASE 
                    WHEN C.New_QT > 0 THEN C.New_QT
                    ELSE Quantity2
                    END
            FROM CHECKERS C -- Actual table, not a table variable!
            WHERE OrderNo = C.OrderNum

現在唯一的問題是,在客戶數據庫中,我無法添加真實表CHECKERS。 我將其添加到測試數據庫中只是為了闡明這些值是否傳遞到表變量中! 這是我不熟悉的表變量的限制嗎? 我很難在在線文檔中找到任何此類限制...

您需要在FROM語句中將訂單添加為INNER JOIN。 嘗試這個:

UPDATE O
SET Quantity2 = CASE 
        WHEN New_QT > 0 THEN New_QT
        ELSE Quantity2
        END
FROM @CHECKERS C
INNER JOIN Orders O on O.OrderNo = C.OrderNum

表變量(@CHECKERS)和實際表(dbo.CHECKERS)具有相同的名稱。 觸發器在他們之間感到困惑。 通過更改觸發器中的操作順序,這變得顯而易見。 然后,我更改了實際表的名稱,一切開始變得更加順利。

我不了解表變量,也沒有在尋找解決方案的幾個小時內在線找到它。

有關常規信息:此觸發器是在Microsoft SQL Server 2005中創建的。也許問題已解決,或者這是a幸。 無論哪種方式,將dbo.CHECKERS的名稱更改為dbo.CHECKME都能為我解決問題。

暫無
暫無

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

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