我认为我的问题最好通过下面的示例类似地提出。
假设我有下表,其中包含有关学校班级和学生的信息。
班级号 | 学生卡 |
---|---|
1 | 3 |
1 | 6 |
1 | 2 |
1 | 6 |
2 | 4 |
2 | 7 |
3 | 6 |
3 | 3 |
3 | 2 |
3 | 5 |
3 | 1 |
我想检索包含 ID 为 3 和 6 的学生的所有学生和班级,即我的结果是:
班级号 | 学生卡 |
---|---|
1 | 3 |
1 | 6 |
1 | 2 |
1 | 6 |
3 | 6 |
3 | 3 |
3 | 2 |
3 | 5 |
3 | 1 |
这可以通过以下查询来实现...
SELECT
*
FROM
table_name
WHERE
class_id IN (SELECT
class_id
FROM
table_name
WHERE
student_id IN (3 , 6)
GROUP BY class_id
HAVING COUNT(DISTINCT student_id) = 2);
我想知道是否可以在不使用子查询的情况下实现上述目标?速度是最重要的,所以我想尽量减少这个选择查询的持续时间。
试图避免子查询可能会导致您走上错误的道路。您确实可以使用子查询编写错误的查询,但您也可以在没有它们的情况下编写错误的查询,以及使用它们编写非常好的查询。
在您的情况下,子查询被用作单独的范围来查找感兴趣的类列表。在获得这些班级学生的相同范围内这样做可能会很混乱且效率低下。
例如,使用的替代方法IN()
仍然需要子查询...
SELECT
student.*
FROM
table_name AS student
INNER JOIN
(
SELECT
class_id
FROM
table_name
WHERE
student_id IN (3 , 6)
GROUP BY
class_id
HAVING
COUNT(DISTINCT student_id) = 2
)
AS class
ON class.class_id = student.class_id
但是,这可能会产生与您已有的查询相似(甚至相同)的计划。
最接近“没有子查询”的方法是使用嵌套查询,您可以说它仍然是子查询,但优化器更容易扩展。
(使用 MySQL 8+)
SELECT
*
FROM
(
SELECT
*,
SUM(CASE WHEN student_id IN (3,6) THEN 1 END)
OVER (PARTITION BY class_id)
AS target_member_count
FROM
table_name
)
scanned
WHERE
target_member_count = 2
在大多数班级不包含学生 3 和/或 6 的情况下,我希望这会慢一些。但你可以尝试一下。
本文收集自互联网,转载请注明来源。
如有侵权,请联系 [email protected] 删除。
我来说两句