Sql-Server

更新多個連接表的視圖

  • January 29, 2016

由於 MSDN 並沒有說太多,如果我執行以下查詢會發生什麼?

update claims set status='Awaiting Auth.'
where status = 'Approved' 

我可以使用ClaimStatusName連結表的列dimClaimStatus來更新通過外鍵引用的主表嗎?

視圖本身查詢多個表,主表是tabData,我也想用上面的查詢更新。我想從 FK 這意味著fiClaimStatus在引用表中更改為. 它是這樣工作的嗎?tabData Approved``dimClaimStatus``Awaiting Auth.

tabData 中的每一行只能有一個視圖行。

這是視圖:

CREATE VIEW [dbo].[Claims] 
AS 
 SELECT mu.MarketUnitName AS MarketUnit, 
        c.CountryName     AS Country, 
        gsp.GSPName       AS GSP, 
        gsp.WCMSKeyNumber AS GspNumber, 
        sl.SLName         AS SL, 
        sl.WCMSKeyNumber  AS SlNumber, 
        m.ModelName       AS Model, 
        m.SalesName       AS [Model-Salesname], 
        s.ClaimStatusName AS [Status], 
        d.Work_Order      AS [Work Order], 
        d.SSN_Number      AS IMEI, 
        .... more columns ....
        idData,         -- PK of main table tabData
        fiSL, 
        fiModel, 
        fiClaimStatus  -- FK to dimClaimStatus
 FROM   tabData AS d 
        INNER JOIN locSL AS sl 
                ON d.fiSL = sl.idSL 
        INNER JOIN locGSP AS gsp 
                ON sl.fiGSP = gsp.idGSP 
        INNER JOIN locCountry AS c 
                ON gsp.fiCountry = c.idCountry 
        INNER JOIN locMarketUnit AS mu 
                ON c.fiMarketUnit = mu.idMarketUnit 
        INNER JOIN modModel AS m 
                ON d.fiModel = m.idModel 
        INNER JOIN dimClaimStatus AS s 
                ON d.fiClaimStatus = s.idClaimStatus 
        INNER JOIN tdefProductType 
                ON d.fiProductType = tdefProductType.idProductType 
        LEFT OUTER JOIN tdefServiceLevel 
                     ON d.fimaxServiceLevel = tdefServiceLevel.idServiceLevel 
        LEFT OUTER JOIN tdefActionCode AS ac 
                     ON d.fimaxActionCode = ac.idActionCode 

更新

由於該表包含 2000 萬條客戶記錄,因此我想先知道在執行它之前會發生什麼。在評論和回答之後,我現在已經執行了。直接結果是:

(1 row(s) affected)

令人驚訝的是,有數千條處於此狀態的記錄現在似乎已更新。

更新 2

實際上它並沒有按預期工作,懷疑(1 row(s) affected)是正確的。僅更新了引用的表。所以現在狀態Approved變成了Awaiting Auth.

結論:

這似乎是避免使用視圖進行更新的最佳方式。這適用於我的情況:

UPDATE tabData 
SET fiClaimStatus = (SELECT idClaimStatus
                    FROM dimClaimStatus
                    WHERE ClaimStatusName = 'Awaiting auth.')
WHERE fiClaimStatus=(SELECT idClaimStatus
                    FROM dimClaimStatus
                    WHERE ClaimStatusName = 'Approved')

一般視圖可更新性

CREATE VIEW (Transact-SQL)文件的關鍵部分是:

通常,數據庫引擎必須能夠明確地跟踪從視圖定義到一個基表的修改。

請注意,即使視圖在技術上是可更新的,但由於查詢處理器推理的限制,它實際上可能無法在實踐中更新。這就是“……數據庫引擎必須能夠……”這句話背後的微妙之處。

確保視圖實際上可更新的最簡單方法是請求更新查詢的預執行(“估計”)計劃。如果出現錯誤,要麼視圖在邏輯上不可更新,要麼查詢處理器無法判斷它是。

自然,請求“估計”計劃不涉及執行查詢。顯示的計劃還將顯示查詢優化器能夠刪除多少視圖定義(因為它是多餘的)。通常,它在這方面做得很好,因此更新視圖計劃可能看起來非常類似於對單個受影響的基表進行簡單更新的計劃。

具體例子

我可以使用連結表dimClaimStatus的**ClaimStatusName列來更新通過外鍵引用的主表嗎?

$$ … $$我想更改tabData中的 fiClaimStatus。

不使用您發布的查詢:

update claims 
set status='Awaiting Auth.'
where status = 'Approved' 

這會更改與視圖的公開列名稱status關聯的基表列。從視圖定義來看,這是表 dimClaimStatus 中列 ClaimStatusName的**別名

執行計劃顯示,dimClaimStatus是通過視圖更新的表:

執行計劃

如果你想更新fiClaimStatus,那就是你需要在更新語句中指定的列。如果這涉及查找,您可能無法直接使用視圖,正如您最初想要的那樣,但您可以編寫如下內容:

update claims 
set fiClaimStatus =
(
   select CS.idClaimStatus
   from dbo.dimClaimStatus AS CS
   where CS.ClaimStatusName = 'Awaiting auth.'
)
where status = 'Approved';`

引用自:https://dba.stackexchange.com/questions/127708