更新多个连接表的视图

Tim*_*ter 6 sql-server-2005 sql-server t-sql view update

由于 MSDN 没有说太多,如果我执行以下查询会发生什么?

update claims set status='Awaiting Auth.'
where status = 'Approved' 
Run Code Online (Sandbox Code Playgroud)

我可以使用ClaimStatusName链接表的列dimClaimStatus来更新通过外键引用的主表吗?

视图本身查询多个表,主表是tabData,我也想用上面的查询更新。我想改变fiClaimStatustabData从FK该手段 Approved在引用表dimClaimStatusAwaiting 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 
Run Code Online (Sandbox Code Playgroud)

更新

由于该表包含 2000 万条客户记录,我想在执行它之前先知道会发生什么。在评论和回答之后,我现在已经执行了。直接结果是:

(1 row(s) affected)
Run Code Online (Sandbox Code Playgroud)

这是令人惊讶的,因为在这种状态下有数千条记录,现在似乎正在更新。

更新 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')
Run Code Online (Sandbox Code Playgroud)

Pau*_*ite 8

一般视图可更新性

CREATE VIEW (Transact-SQL)文档的关键部分是:

通常,数据库引擎必须能够清楚地跟踪从视图定义到一个基表的修改。

请注意,即使视图在技术上是可更新的,但由于查询处理器推理的限制,它实际上可能无法更新。这就是短语背后的微妙之处,“...数据库引擎必须能够...”

确保视图实际上可更新的最简单方法是为更新查询请求执行前(“估计”)计划。如果出现错误,要么视图在逻辑上不可更新,要么查询处理器无法判断它是。

自然地,请求“估计”计划不涉及执行查询。显示的计划还将显示查询优化器能够删除多少视图定义(因为它是多余的)。通常,它在这方面做得很好,因此更新视图计划可能看起来非常类似于对单个受影响的基表进行简单更新的计划。

具体例子

我可以使用链接表dimClaimStatusClaimStatusName列更新通过外键引用的主表吗?[...] 我想更改tabData中的 fiClaimStatus。

不使用您发布的查询:

update claims 
set status='Awaiting Auth.'
where status = 'Approved' 
Run Code Online (Sandbox Code Playgroud)

这会更改与视图的公开列名称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';`
Run Code Online (Sandbox Code Playgroud)