如何在 SQL Server 中的 UPDATE 查询的子查询中引用表变量

Posted

技术标签:

【中文标题】如何在 SQL Server 中的 UPDATE 查询的子查询中引用表变量【英文标题】:How to reference a table variable in sub-query of an UPDATE query in SQL Server 【发布时间】:2015-09-02 14:34:18 【问题描述】:

我在一个存储过程中有一个 UPDATE 查询,我需要在其中更新一个已经被一些数据填充的表变量。由于在子查询中引用了表变量,即在子查询中引用了@daysPerEmail.ProductId,因此该查询(如下面的代码)给出了错误。我尝试使用 UPDATE @daysPerEmail d SET LastEmailDate... 中的表变量别名,但没有帮助。

问题:如何重写查询,以便在子查询中正确引用 ProductId 的表变量列?

UPDATE @daysPerEmail SET LastEmailDate = (SELECT max(ActionDate) FROM 
        useractionsreport  WHERE ProductId = @daysPerEmail.ProductId 
       and ActionTypeId = @userActionTypeId );

更新 1

为了在 SSMS 中重现这一点,我使用以下查询。 SSMS 给出错误提示 Must declare the scalar variable "@daysPerEmail".

DECLARE @daysPerEmail TABLE (
    VendorId INT,
    DaysPerEmail SMALLINT,
    LastEmailDate DATE,
    ProductId INT 
)

INSERT INTO @daysPerEmail (VendorId, DaysPerEmail, LastEmailDate, ProductId)
    VALUES (10, 5, NULL, 11), (12, 3, NULL, 15), (14, 1, NULL, 22);

UPDATE @daysPerEmail
SET LastEmailDate = (SELECT
    MAX(ActionDate)
FROM UserActionsReport   
WHERE ProductId = @daysPerEmail.ProductId
AND ActionTypeId = 2);

更新 2

Paolo 的回答按预期工作,但我还找到了另一个使用查询的简单解决方案,如下所示。我所要做的就是为 @daysPerEmail 表变量中的 ProductId 列提供一个唯一的名称。我将名称更改为 ProdId,它在 UPDATE 查询涉及的任何表中都不存在。然后我不必在子查询中引用表变量,因为 ProdId 列名仅在 UPDATE 查询中使用的表中的 @daysPerEmail 表变量中找到。

 DECLARE @daysPerEmail TABLE (
    VendorId INT,
    DaysPerEmail SMALLINT,
    LastEmailDate DATE,
    ProdId INT 
)

INSERT INTO @daysPerEmail (VendorId, DaysPerEmail, LastEmailDate,ProdId)
    VALUES (78, 5, NULL, 2), (78, 3, NULL, 387), (78, 1, NULL, 295);

UPDATE @daysPerEmail
SET LastEmailDate = (SELECT
    MAX(ActionDate)
FROM UserActionsReport   
WHERE ProductId = ProdId
AND ActionTypeId = 2);

【问题讨论】:

这是存储过程的表类型变量吗???您的更新声明是有效的。 是的。这是一个表变量,如declare @daysPerEmail (ProductId int, LastEmailDate Date) 如果您仔细查看过程定义,过程中的表类型变量为 READONLY ,您需要从该表类型变量 (select * into #temp from @daysPerEmail) 创建另一个表,然后更新该 @ 987654330@ 表。此表变量将仅为 READONLY。 这是无效的,因为 SSMS 给出了一个错误提示 Must declare the scalar variable "@daysPerEmail",即使它之前已经在存储过程中声明了。 你有一个列 @daysPerEmail.ProductId 的引用,它不在表声明本身中。 【参考方案1】:

使用方括号,例如 [@daysPerEmail] 而不是 @daysPerEmail

这样您就可以将别名与表变量一起使用。

【讨论】:

【参考方案2】:

加入更新怎么样? 如果我没记错的话,它不符合标准,但SQL-Server 允许:

UPDATE  X
SET     LastEmailDate = Z.MaxActionDate
FROM    @daysPerEmail AS X
        JOIN (
            SELECT  MAX(Y.ActionDate) AS MaxActionDate
                    , Y.ProductId
            FROM    UserActionsReport AS Y
            WHERE   ActionTypeId = 2
            GROUP BY Y.ProductId
        ) AS Z ON Z.ProductId = X.ProductId;

【讨论】:

在这种情况下 IIRC 是什么? 如果我没记错的话 另一个有效的解决方案是在定义表变量@daysPerEmail 时简单地将 ProductId 列名称更改为 ProdId。这意味着不需要在子查询中引用表变量,因为 ProdId 列名在 UPDATE 查询的所有表中都是唯一的。 是的,我现在明白了。听起来像是 SQL Server 中的一些重要术语。哈哈。

以上是关于如何在 SQL Server 中的 UPDATE 查询的子查询中引用表变量的主要内容,如果未能解决你的问题,请参考以下文章