【问题标题】:Why not "Invalid column name XYZ" error in subquery; although column name is not in subquery table?为什么子查询中没有“Invalid column name XYZ”错误;虽然列名不在子查询表中?
【发布时间】:2010-01-21 15:46:27
【问题描述】:

当我运行这个查询时

SELECT CustomerId FROM Stocks.dbo.Suppliers

它给了我这个错误。列名“CustomerId”无效。此错误有效,因为 Suppliers 表中没有 CustomerId 列;但是当我在子查询中使用相同的查询时,它不会给出任何错误例如

SELECT * 
  FROM SomeOtherDb.dbo.Customer 
 WHERE CustomerId In( SELECT CustomerId 
                        FROM Stocks.dbo.Suppliers)

这里我期待同样的错误“无效的列名”,但查询运行没有任何错误。

完全限定名称只是约定两个数据库都在同一台服务器上。

CustomerId 确实存在于 SomeOtherDb.dbo.Customer 表中,但不存在于子查询中。

为什么会出现这种行为?这与子查询有关吗?

谢谢。

【问题讨论】:

  • 在任何一种情况下都会向我抛出无效列错误。完全限定名称只是约定还是通过链接服务器?
  • 完全限定名只是一个约定。两个数据库都在同一台服务器上。

标签: sql sql-server sql-server-2005 tsql subquery


【解决方案1】:

子查询从外部查询继承列。

我猜您的 SomeOtherDb.dbo.Customer 确实有一个 CustomerId 列(这也可能从名称上看)。

这也可能意味着您没有对子查询执行您想要对其执行的操作 - 如果子查询中的表没有 CustomerId 列(看起来确实如此,否则运行时不会出现错误子查询本身),然后子查询选择并返回外部 CustomerId,由于这是子查询中的唯一列,因此子查询无用。

【讨论】:

  • 是的,你是对的 SomeOtherDb.dbo.Customer 有 CustomerId 列。
  • 我自己也遇到过几次,虽然答案是有道理的,但我认为它在 SQL Server 中的设计很糟糕(无论它是否完全实现了 ISO SQL 标准)。我认为在引用父查询中的列时要求子查询使用别名会更安全。我的同事由于上述子查询中的拼写错误而错误地更新了生产表中的所有行,因此经历了相关的悲剧。欢闹(并从备份中恢复)随之而来:)
  • 通过为每列显式定义表(或表别名)是一个很好的做法:它可以避免您的子查询从不正确的表中获取列,并且在常规连接(没有子查询)时也会避免以防有人创建新列时出现名称冲突。
  • 我不买你卖的 Bandi-T。无论如何,无效的列规范都应该引发错误。否则,这可能会导致难以调试的问题。我在 Oracle 上遇到过这种情况。
  • “子查询从外部查询继承列” - 这是否记录在某处?
【解决方案2】:

您的问题(“为什么没有错误”)的答案在上面,但可能对将来如何避免此类问题有所帮助:不要使用子查询来执行此操作,而是使用左连接:

SELECT C.* 
FROM SomeOtherDb.dbo.Customer AS C
LEFT JOIN Stocks.dbo.Suppliers AS S ON C.CustomerId = S.CustomerId
WHERE S.CustomerID Is Null

这个查询,当然,当使用可能的连接构造时,将始终执行与原始查询一样或更好的查询 - 并且您还可以获得避免上述讨厌问题的额外好处。因为在这个构造中你自然会使用表名,当出现问题时会更加明显,比如等号两边的表名相同。子查询很烂,我一直在反对它们。

(也就是说,我知道很多人都在反对别名,我在上面用它来简化/压缩代码:))

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多