具有相关子查询的更新查询不能通过表别名

Posted

技术标签:

【中文标题】具有相关子查询的更新查询不能通过表别名【英文标题】:Update query with correlated subquery can't go through table alias 【发布时间】:2020-09-23 08:58:09 【问题描述】:

我的 SQL Server 上有这个更新查询

UPDATE BK_TT_DELIVERY_PLAN TDP
SET (PACK_TYPE) = 
            (SELECT OPD.PACKING_TYPE
               FROM TT_OM_PACK_DISCREPANCY OPD
              WHERE ISNULL(TDP.PO_REF,TDP.PO_NUMBER) = OPD.PO_NUMBER
                    AND TDP.PO_ITEM = ODP.PO_ITEM)
WHERE 
    EXISTS (SELECT 1
            FROM TT_OM_PACK_DISCREPANCY OPD
            WHERE ISNULL(TDP.PO_REF,TDP.PO_NUMBER) = OPD.PO_NUMBER
              AND TDP.PO_ITEM = ODP.PO_ITEM) 

当我尝试执行时,我总是收到此错误:

查找错误 - SQL Server 数据库错误:“TDP”附近的语法不正确

我在 Oracle 上试了一下,效果很好。

此问题的任何解决方法?

谢谢。

【问题讨论】:

【参考方案1】:

您不在UPDATE 子句中为表设置别名,而是在FROM 中这样做。由于此语句中没有FROM,因此您不要为表指定别名。但是,这意味着您必须将查询中的所有别名更改为表的名称:

UPDATE dbo.BK_TT_DELIVERY_PLAN
   SET (PACK_TYPE) = 
            (SELECT OPD.PACKING_TYPE
               FROM TT_OM_PACK_DISCREPANCY OPD
              WHERE ISNULL(BK_TT_DELIVERY_PLAN.PO_REF,BK_TT_DELIVERY_PLAN.PO_NUMBER) = OPD.PO_NUMBER
                    AND BK_TT_DELIVERY_PLAN.PO_ITEM = ODP.PO_ITEM)
 WHERE EXISTS
      (SELECT 1
         FROM TT_OM_PACK_DISCREPANCY OPD
              WHERE ISNULL(BK_TT_DELIVERY_PLAN.PO_REF,BK_TT_DELIVERY_PLAN.PO_NUMBER) = OPD.PO_NUMBER
                    AND BK_TT_DELIVERY_PLAN.PO_ITEM = ODP.PO_ITEM);

因此使用FROM 可能是一个更好的主意,然后在UPDATE 子句中引用别名:

UPDATE TDP
   SET (PACK_TYPE) = 
            (SELECT OPD.PACKING_TYPE
               FROM TT_OM_PACK_DISCREPANCY OPD
              WHERE ISNULL(TDP.PO_REF,TDP.PO_NUMBER) = OPD.PO_NUMBER
                    AND TDP.PO_ITEM = ODP.PO_ITEM)
FROM dbo.BK_TT_DELIVERY_PLAN TDP
WHERE EXISTS
      (SELECT 1
         FROM TT_OM_PACK_DISCREPANCY OPD
              WHERE ISNULL(TDP.PO_REF,TDP.PO_NUMBER) = OPD.PO_NUMBER
                    AND TDP.PO_ITEM = OPD.PO_ITEM);

另外注意,您不应该使用ISNULLWHERE(或ON),因为它会导致查询变得不可搜索。使用正确的布尔逻辑。同样,使用 JOIN 而不是 2 个子查询,这似乎也可以变得更小。

UPDATE TDP
SET PACK_TYPE = OPD.PACKING_TYPE
FROM dbo.BK_TT_DELIVERY_PLAN TDP
     JOIN TT_OM_PACK_DISCREPANCY OPD ON (TDP.PO_REF = OPD.PO_NUMBER 
                                     OR  (TDP.PO_REF IS NULL AND TDP.PO_NUMBER = OPD.PO_NUMBER))
                                    AND TDP.PO_ITEM = OPD.PO_ITEM;

【讨论】:

使用第二个查询返回:无法绑定多部分标识符“ODP.PO_ITEM”。 正如 Gordon 刚刚通过他们的编辑 @Syns 演示的那样,这确实是您原始代码中的一个印刷错误。你有AND TDP.PO_ITEM = ODP.PO_ITEM,但将对象TT_OM_PACK_DISCREPANCY别名为OPD,而不是ODP;因此错误。 @lamu 哦该死,我没有注意到印刷错误。我的错。感谢指正 @gordon-linoff 谢谢,这是我的新见解,我将使用第三个查询,【参考方案2】:

简单查询,请按照以下查询。在哪里使用联合查询结果和更新记录。

UPDATE TDP
SET TDP.PACK_TYPE = OPD.PACKING_TYPE
FROM dbo.BK_TT_DELIVERY_PLAN TDP
LEFT OUTER JOIN TT_OM_PACK_DISCREPANCY OPD ON ISNULL(TDP.PO_REF,TDP.PO_NUMBER) = OPD.PO_NUMBER AND TDP.PO_ITEM = ODP.PO_ITEM
WHERE OPD.PACKING_TYPE IS NOT null

【讨论】:

以上是关于具有相关子查询的更新查询不能通过表别名的主要内容,如果未能解决你的问题,请参考以下文章

子查询

Mysql数据库理论基础之五--SELECT单多表查询子查询别名

连接查询与子查询

子查询(嵌套子查询)

sql查询语句学习,多表查询和子查询以及连接查询

使用子查询更新语句