Navicat 博客

一些最常见的 SQL 查询错误 - 第 4 部分 2022 年 5 月 11 日,由 Robert Gravelle 撰写

捣乱的子查询

在这个关于“常见的 SQL 查询错误”的系列中,我们已经看了几个 SQL 查询示例,这些查询在第一次检查时看起来非常可靠,但它们可能会导致错误的结果和/或性能降低。上周,我们学习了放置谓词的位置如何对查询执行产生负面影响,尤其是在外部联接中。今天将重点介绍子查询,以及当对任何基础表进行更改时它们如何破坏 SQL 语句。

单个值与多个值子查询

在比较单个值和多个值子查询之前,我们应该简要介绍一下子查询是什么。子查询是一个嵌套在较大的查询中的完整 SQL 查询。子查询可以放在 SELECT、FROM 和 WHERE 子句中。

既然我们知道了子查询是什么以及它在查询中的位置,应该注意的是,与任何 SELECT 查询一样,子查询返回可能是一行,亦可能是多行。这种区别非常重要,因为它会影响你编写查询语句的方式。例如,以下是在 Navicat Premium 16 中针对 Sakila 样本数据库的查询,它获取了电影“ALONE TRIP”的所有演员:

subquery_single_row (98K)

由于应该只有一部名为“ALONE TRIP”的电影,我们可以使用等号(=)运算符来匹配 film_id。

将上述查询与以下查询进行对比:

subquery_multiple_rows (46K)

在这种情况下,子查询选择电影的所有演员。当然,这个子查询将返回多行。此种情况下,我们应该使用 IN() 函数来匹配 actor_id

单行子查询如何破坏

如前所述,可以将子查询放在 SELECT 子句中以获取与主查询表相关的列。例如,以下在 Navicat Data Modeler 中两个相关的 products 和 factories 表:

products_factories_diagram (22K)

products 和 factories 表使用共同的 sku 字段链接。

现在,让我们编写一个查询来提取每个产品的 factory_id。方法是使用相关子查询编写查询以检索产品 factory_id

product_query (31K)

请注意,这里的重点是说明一种更有效的方法来检索相同的信息。无论如何,我们得到了正确的结果集,一切都很好。

该查询将继续完美运行,直到公司决定随着销售额增加而建立新工厂的那一天到来:

new_factory (11K)

factory 表中的额外行导致我们的查询现在发生错误:

error_message (49K)

该错误告诉我们外部查询需要一个标量值,但我们的子查询返回了一个结果集。我们可以使用 JOIN 解决这个问题并列出制造每种产品的所有工厂:

query_with_join (30K)

还有一件事...

请注意,在针对子查询测试列或表达式的任何子句中都可能出现相同的错误,例如“column = (SELECT value FROM Table)”。在这种情况下,解决方案是使用 IN() 函数而不是相等(=)运算符。

Navicat 文章
频道条目
分享
文章归档