SQL Server 更新语句基于具有多个值的 Select 语句

Posted

技术标签:

【中文标题】SQL Server 更新语句基于具有多个值的 Select 语句【英文标题】:SQL Server update statement based on Select Statement with multiple values 【发布时间】:2020-02-05 22:23:23 【问题描述】:

我有一个运行良好的 Select 语句,产生 7636 行:

SELECT c.ClientId
    FROM   dbo.tblTreatment e
      JOIN dbo.tblProgramAssessment pa
    ON pa.TreatmentID = e.TreatmentId
      JOIN #Client c
    ON c.ClientId = e.ClientId
      LEFT JOIN dbo.tblCessationOfTreatment ct
    ON ct.TreatmentId = e.TreatmentId
      LEFT JOIN dbo.tblClientGP m
    ON m.ClientId = c.ClientId
    WHERE  e.IsOpen = 1 
    AND    e.IsDeleted = 0 
    AND    ct.CessationDate is null
    AND    c.IsDeceased = 0 

我正在尝试更新这 7636 行,但它改为更新 7446 行。在我(有限的)理解中,这可能是由于 clientid 的某种原因。这是更新声明:

UPDATE 
    #Client
SET 
    ToMigrate = 1
    , OpenTreatmentEpisodes = 1
WHERE 
    clientid in
    (SELECT c.ClientId
    FROM   dbo.tblTreatment e
      JOIN dbo.tblProgramAssessment pa
    ON pa.TreatmentID = e.TreatmentId
      JOIN #Client c
    ON c.ClientId = e.ClientId
      LEFT JOIN dbo.tblCessationOfTreatment ct
    ON ct.TreatmentId = e.TreatmentId
      LEFT JOIN dbo.tblClientGP m
    ON m.ClientId = c.ClientId
    WHERE  e.IsOpen = 1 
    AND    e.IsDeleted = 0 
    AND    ct.CessationDate is null
    AND    c.IsDeceased = 0  
)

如果我将“IN”更改为“=”,我会收到一条错误消息: 子查询返回超过 1 个值。当子查询跟随 =、!=、、>= 或子查询用作表达式时,这是不允许的。 声明已终止。

1) 我真的不明白为什么 7446 和 7636 行之间存在差异。 2) 如何只更新 select 语句中的 7636 行?

提前谢谢你!

【问题讨论】:

您的结果表明您在 #Client 中有一些重复的 clientid #Client 中重复的 clientid 值是有道理的 - 谢谢@Nick!尽管如此,我如何编写一个 SQL 查询来根据 select 语句只更新 7637 行? 【参考方案1】:

正如 Nick 所说,您可能在表 #Client 中重复了 clientid。因此,IN 子查询返回的某些元素与外部查询中的几行匹配,导致不需要的行被更新。

我认为您可以通过利用 SQL Server 可更新 CTE 的功能来解决此问题。这可以通过将您的 SELECT 查询转换为 CTE,然后将 UPDATE 直接转换为 CTE 来实现(请注意,要使其正常工作,CTE 必须返回需要更新的列)。

WITH cte AS (
    SELECT c.ToMigrate, c.OpenTreatmentEpisodes
    FROM dbo.tblTreatment e
    INNER JOIN dbo.tblProgramAssessment pa ON pa.TreatmentID = e.TreatmentId
    INNER JOIN #Client c ON c.ClientId = e.ClientId
    LEFT JOIN dbo.tblCessationOfTreatment ct ON ct.TreatmentId = e.TreatmentId
    LEFT JOIN dbo.tblClientGP m ON m.ClientId = c.ClientId
    WHERE  
           e.IsOpen = 1 
           AND e.IsDeleted = 0 
           AND ct.CessationDate is null
           AND c.IsDeceased = 0 
)
UPDATE cte SET ToMigrate = 1, OpenTreatmentEpisodes = 1

【讨论】:

了解@GMB,必须在选择中指定 ToMigrate 和 OpenTreatmentEpisodes。独立执行 Select 语句会产生 7636 行,运行 WITH cte AS (SELECT ..) UPDATE cte Set ToMigrate = 1, OpenTreatmentEpisodes = 1 会产生 7446 行。如果我将“UPDATE cte Set ToMigrate = 1, OpenTreatmentEpisodes = 1”更改为“SELECT * FROM CTE”,它将产生 7636 行。我了解重复 clientid 的可能性,所以我运行了这个:“SELECT COUNT(*),clientid FROM #Client where OpenTreatmentEpisodes = 1 GROUP BY clientid HAVING COUNT(clientid) > 1" (7446 OpenTreatmentEpisodes=1),0 行。 PS - 简单来说,WITH cte 脚本产生 7446 行。

以上是关于SQL Server 更新语句基于具有多个值的 Select 语句的主要内容,如果未能解决你的问题,请参考以下文章

使用两个可以返回多个值的子查询的 SQL 之间的语句

使用JPA在Sql中具有不同值的多个语句where子句

ms sql server字符串与另一个具有多个值的字符串进行比较

SQL:如果存在则更新,否则插入...但对于具有不同值的多行

具有多个值的 CASE 语句

SQL Server:具有多个可能条件的案例语句中的模式匹配