Navicat 博客

相关子查询 2023 年 2 月 2 日,由 Robert Gravelle 撰写

子查询可以分为两类:

  • 非相关(简单)子查询独立于其包含(外部)语句获取其结果。
  • 相关子查询引用其外部查询的值以便执行。

当非相关子查询执行时(独立于外部查询),首先执行子查询,然后将其结果传递给外部查询。与此同时,相关子查询通常会在执行之前从其外部查询中获取值。当子查询返回结果时,它将其结果传递给外部查询。

现在我们知道相关子查询和非相关子查询之间的区别,本文将介绍如何在 Navicat Premium 16 中编写相关子查询。

语法和用法

相关子查询会计算父语句处理的每一行一次。父语句可以是 SELECT、UPDATE 或 DELETE 语句。以下是 SELECT 查询的语法:

SELECT column1, column2, ....
FROM table1 outer
WHERE column1 operator
  (SELECT column1, column2
   FROM table2
   WHERE expr1 = outer.expr2);

相关子查询是一种读取表中每一行并将每一行中的值与相关数据进行比较的方法。只要子查询必须为主查询考虑的每个候选行返回不同的结果或结果集,就会使用它。换句话说,你可以使用相关子查询来回答一个多部分问题,其答案取决于父语句处理的每一行中的值。

实际示例

这是来自 stackoverflow 的一个相当巧妙的查询,在 Sakila 示例数据库提取每个国家或地区观看次数最多的电影。

第一步是计算每部电影在每个国家或地区的观看次数。以下是 SELECT 语句:

SELECT 
  F.title AS title, 
  CO.country_id AS country_id,
  CO.country AS country_name, 
  count(F.film_id) as times
FROM customer C INNER JOIN address A ON C.address_id = A.address_id
INNER JOIN city CI ON A.city_id = CI.city_id
INNER JOIN country CO ON CI.country_id = CO.country_id
INNER JOIN rental R ON C.customer_id = R.customer_id
INNER JOIN inventory I ON R.inventory_id = I.inventory_id
INNER JOIN film F ON I.film_id = F.film_id
GROUP BY F.film_id, CO.country_id;

以下是 Navicat Premium 16 中的上述查询和结果:

most viewed film per country inner query (170K)

下一步是将上述结果转换为国家或地区的列表,连同观看次数最多的电影名称和观看次数。以下是含有相关子查询的完整查询,并附有解释:

most viewed film per country correlated query (159K)

解释:

  • 子查询:提取按国家分组的电影计数列表。
  • GROUP_CONCAT(title ORDER BY times DESC SEPARATOR '|||') 返回该“行”中的所有标题,观看次数最多的标题排在第一位。而分隔符无关紧要,只要不出现在标题中即可。
  • SUBSTRING_INDEX('...', '|||', 1) 提取字符串的第一部分,直到找到“|||”,在本例中是第一个(因此也是观看次数最多的)标题。

关于相关子查询的最后想法

在今天的文章中,我们学习了如何使用 Navicat Premium 16 编写相关子查询。预先提醒一下,相关子查询可能很慢。然而,适当的优化可以显着提高它们的速度。

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