【问题标题】:How to verify if subquery is correct?如何验证子查询是否正确?
【发布时间】:2013-06-11 12:26:00
【问题描述】:

我有两张桌子:

  • SupplierLocation 与列 Id | SupplierId | ThirdPartyId

  • Supplier 与列 Id | Company

我们使用的是 SQL Server 2008。我正在尝试纠正一些写得不好的查询。例如,即使子查询中的列名不正确(Supplier 表没有 ThirdPartyId),以下查询也会运行而不会引发错误:

SELECT * 
FROM SupplierLocation 
WHERE SupplierId IN (SELECT ThirdPartyId 
                     FROM Supplier 
                     WHERE Id = @id)

有没有办法在这样的查询中检查子查询是否正确?

谢谢!

【问题讨论】:

  • 运行子查询看看返回什么结果?反转 IN/NOT IN 以查看计数是否如您预期的那样受到影响。
  • SupplierLocation 表中必须有一个ThirdPartyId 列,这使得SQL 有效,即使它是荒谬的。除了知道数据模型和知道查询应该做什么之外,没有其他方法可以检测到这一点。
  • @JC。 - 有这样一列 - 请参阅问题中的第一个要点。
  • 对。那么有解释为什么 SQL 验证。但是仍然没有找到语法有效但功能损坏的 SQL 的神奇方法。

标签: sql-server-2008 tsql subquery syntax-error in-clause


【解决方案1】:

使用别名并限定列名。

SELECT * 
FROM SupplierLocation as SL
WHERE SL.SupplierId IN (SELECT S.ThirdPartyId 
                     FROM Supplier as S
                     WHERE S.Id = @id)

在子查询中包含来自不同来源的数据是完全合法的:

SELECT *, ( select Id + ThirdParty + @Id from Supplier where Id = @Id ) as GuessWhat
FROM SupplierLocation as SL
WHERE SL.SupplierId IN (SELECT S.ThirdPartyId 
                     FROM Supplier as S
                     WHERE S.Id = @id)

如果您没有明确说明来源,那么您可能会惊讶地发现 SQL Server 可以解决什么问题。每当您使用 JOIN 来限定所有列名时,这是一种很好的做法。

SSMS 中的 Parse 工具会检测到一些(但不是全部)错误。这是一个方便的起点。

【讨论】:

  • 是的,我也是这么想的。我们需要检查大量脚本并验证这些字段。现在手动更正它们并添加别名是解决方案。这样,如果将来有人更改了列名并且没有在存储过程中进行更改,则会出现语法错误。没有别名,代码在语法上是正确的并且会运行,这是不好的。
  • 在像 Notepad++ 这样好的文本编辑器中加载脚本并进行一些正则表达式搜索以识别子查询可能有助于减少一些工作。
【解决方案2】:

虽然不是针对此问题的通用解决方案,但可以重写提供的示例,以便查询编译器捕获类似的错误。

一种方法是限定列名。

SELECT * 
FROM SupplierLocation 
WHERE SupplierId IN (SELECT Supplier.ThirdPartyId 
    FROM Supplier 
    WHERE Id = @id)

另一个是使用 where exists 而不是 where in

SELECT * 
FROM SupplierLocation 
WHERE EXISTS (SELECT *
    FROM Supplier 
    WHERE ID = SupplierID
    AND ID = @ID)

(当然,在这个例子中,子查询甚至不是必需的。可以直接对照@ID 变量检查 SupplierID 列)

【讨论】:

  • 感谢 JC,这是一个类似于 HABO 的解决方案,也是我的想法,用于限定列。我想我们会努力的。
  • 实际上,在使用错误的列名时,WHERE EXISTS 并不比 WHERE IN 更安全。合格的列名是 imo 的最佳选择。
  • WHERE EXISTS 可能更安全一些,因为不合格的WHERE ID=IDWHERE ID IN (SELECT ID 更明显错误
【解决方案3】:

一句话:没有——至少,没有简单的方式。

如果代码运行时没有抛出错误(但您碰巧知道输出不正确),那么应用程序逻辑中有错误。

如果代码运行时没有抛出错误,并且您不知道它是否正常工作,那么您就无法挥动魔法棒来验证它。

这就是测试的目的:检查运行的代码是否正常工作。

代码审查也有助于实现这一目标。

【讨论】:

    【解决方案4】:

    这不应该发生,但我可以猜到它可能发生的一些原因:

    1. SupplierLocation 为空,因此查询优化器编译的计划根本不包括子查询。

    2. 1234563列。
    3. 服务器不知何故使用了缓存计划(旧版本),没有提及不存在的列。

    似乎更有可能实际上发生了错误,但由于某种原因您没有看到它。

    【讨论】:

    • 如果 ThirdPartyId 在 SupplierLocation 表中,则子查询将返回一个重复包含相同值的行集。如果 ThirdPartyId 列恰好等于 SupplierId 列,则查询将返回这些行。否则它将不返回任何内容。但查询在语法上仍然有效。
    • 是的,我错过了这种可能性。这是最有可能的情况。
    • 这些都不是真正的可能性。 SQL Server 不会在编译时评估12(除了获得估计的行数)它编译的计划即使在表中插入和删除行仍然有效。回复:3 如果架构发生更改,则所有相关的缓存计划都会自动删除。
    猜你喜欢
    • 2023-03-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-06-02
    • 2016-10-21
    • 2023-03-25
    • 1970-01-01
    • 2021-12-09
    相关资源
    最近更新 更多