SQL Server无法使用子查询更新表

时间:2018-03-15 21:09:17

标签: sql-server tsql sql-update

我正在尝试更新名为@deletedRecords的临时表,如下所示:

![enter image description here

使用名为log的表中的数据,如下所示:

enter image description here

KeyValue表格中的logID中的@deletedRecords相同。

@deletedRecords中有一列用于任何特定键值的每个FieldName。

我尝试使用以下查询提取值:

UPDATE @deletedRecords
SET PatientName = (SELECT ACL.OldValue WHERE ACL.FieldName = 'CptCode'),
    ChargeNotes = (SELECT ACL.OldValue WHERE ACL.FieldName = 'ChargeNotes'),
    Units = (SELECT ACL.OldValue WHERE ACL.FieldName = 'Units'),
    ChargeStatusID = (SELECT ACL.OldValue WHERE ACL.FieldName = 'Units')
FROM Log ACL
JOIN @deletedRecords DR ON ACL.KeyValue = DR.ID
WHERE ACL.TableName = 'BillingCharge'
  AND ACL.EventType = 'DELETE'

但是,当我运行查询时,@deletedRecords中要更新的所有列都为空。有人可以帮我解释一下我错过的东西吗?

提前致谢。

编辑:

为了回应@Yogesh Sharma的回答,我选择使用CTE方法。我希望使用CTE中的值连接到其他表并在更新期间提取它们的值。

e.g。 Log表不包含StatusName的旧值,但它包含ChargeStatusID,可用于连接到包含该信息的另一个表,例如此表{{ 1}}:

enter image description here

因此,我将@Yogesh Sharma的代码修改为以下内容:

ChargeStatus

但是,一旦我添加了辅助连接,所有更新的值都会返回null,就像@Yogesh Sharma的建议实现之前一样。

3 个答案:

答案 0 :(得分:0)

您的查询不起作用,因为DR中的每一行都执行了多次UPDATE,只考虑查询的最后三行中指定的条件(而不是子查询中指定的条件)。保留在表中的值是与上次执行中使用的ACL行对应的值(并且无法控制执行的顺序)。如果对于上次执行中使用的ACL行,子查询返回NULL,则会得到NULL结果。

请参阅https://docs.microsoft.com/en-us/sql/t-sql/queries/update-transact-sql主题中的示例,其中显示“如果语句包含未以这样的方式指定的FROM子句,那么UPDATE语句的结果是未定义的,即每个语句只有一个值可用更新的列出现,即UPDATE语句不确定。“。

您应该像这样重写您的查询:

UPDATE @deletedRecords
SET PatientName = (
        SELECT ACL.OldValue FROM Log ACL 
        WHERE ACL.FieldName = 'CptCode' AND ACL.KeyValue = DR.ID
        AND ACL.TableName = 'BillingCharge' AND ACL.EventType = 'DELETE'
    ),
    ChargeNotes = (
        SELECT ACL.OldValue FROM Log ACL
        WHERE ACL.FieldName = 'ChargeNotes' AND ACL.KeyValue = DR.ID
        AND ACL.TableName = 'BillingCharge' AND ACL.EventType = 'DELETE'
    ),
    Units = (
        SELECT ACL.OldValue FROM Log ACL 
        WHERE ACL.FieldName = 'Units' AND ACL.KeyValue = DR.ID
        AND ACL.TableName = 'BillingCharge' AND ACL.EventType = 'DELETE'
    ),
    ChargeStatusID = (
        SELECT ACL.OldValue FROM Log ACL 
        WHERE ACL.FieldName = 'Units' AND ACL.KeyValue = DR.ID
        AND ACL.TableName = 'BillingCharge' AND ACL.EventType = 'DELETE'
    )
FROM @deletedRecords DR

答案 1 :(得分:0)

您需要为log表执行一些条件聚合并执行JOIN以更新临时表@deletedRecords记录

因此,条件方法可以通过CTESubquery

实现
WITH cte AS
(
    SELECT KeyValue,
           MAX(CASE WHEN FieldName = 'CptCode' THEN OldValue END) PatientName,
           MAX(CASE WHEN FieldName = 'ChargeNotes' THEN OldValue END) ChargeNotes, 
           ...
    FROM Log
    WHERE TableName = 'BillingCharge' AND EventType = 'DELETE'
    GROUP BY KeyValue 
)

UPDATE d 
       SET d.PatientName = c.PatientName,
           ... 
FROM @deletedRecords d
INNER JOIN cte c ON c.KeyValue = d.ID

另一种方法是通过correlation方法

更新临时表
UPDATE d
       SET d.PatientName = (SELECT TOP 1 OldValue FROM Log WHERE KeyValue = d.ID AND 
             TableName = 'BillingCharge' AND EventType = 'DELETE' AND FieldName = 'CptCode'),
           d.ChargeNotes= (SELECT TOP 1 OldValue FROM Log WHERE KeyValue = d.ID AND 
             TableName = 'BillingCharge' AND EventType = 'DELETE' AND FieldName = 'ChargeNotes'),
            ...
FROM @deletedRecords d

答案 2 :(得分:0)

如果您的更新列是NULL,则可能是以下原因:

  • 由于您正在执行INNER JOIN,因此记录可能无法通过其加入列正确加入。确保两个表在连接列上具有相同的值。
  • 由于您使用WHERE条款进行过滤,因此记录可能无法满足您的TableNameEventType过滤条件。确保他们之间有成功INNER JOIN 的记录,他们拥有提供的TableNameEventType
  • 您所指定的值为NULL。确保子查询返回非空值。
  • 表格参考已关闭。在SQL Server中更新表时,如果使用的话,请始终使用更新表别名。

使用

UPDATE DR SET
    YourColumn = Value
FROM
    Log ACL
    JOIN @deletedRecords DR ON -...

而不是

UPDATE @deletedRecords SET
    YourColumn = Value
FROM
    Log ACL
    JOIN @deletedRecords DR ON -...
  • 确保您检查另一个批处理,脚本或过程中的变量表值。变量表范围仅限于当前批处理或过程,而只要会话处于活动状态,临时表就会保留。
  • 确保在更新后没有其他声明将这些值设置为NULL。还要留意您的交易(可能不会被提交或回滚)。