我不相信临时表是必要的。如果我们无法获得可接受的性能,我们真的只会走那条路。
根据您的查询,我们收集您的架构如下所示:
group (id INT PK, gid INT, mid INT)
items (id INT PK, item_id INT, mid INT)
members (id INT PK, email VARCHAR)
看起来您的group
表实际上是一个“成员”表,它解决/实现了一个组和一个人之间的多对多关系。(也就是说,一个人可以是零个、一个或多个组的成员;一个组可以有零个或多个人作为成员。)
group
您在和之间使用 LEFT JOIN members
。当没有匹配的成员时,这将为组返回一行(返回 group.id),members.email 为 NULL(这可能是您想要的)。但如果您只想返回电子邮件地址,则可以将其更改为 INNER JOIN。
NOT EXISTS 谓词可以替换为 OUTER JOIN 和从 JOINED 表返回的 NULL 值的测试。如果group.gid
and/oritems.item_id
列是数字数据类型,那么您可以从谓词中的整数文字周围删除引号。
这是一个替代方案,它将返回一个等效的结果集,并且可能表现更好:
SELECT m.email
, g.id
FROM members m
JOIN group g ON g.mid = m.id AND g.gid = 1
LEFT
JOIN items i ON i.mid = m.id AND i.item_id = 5
WHERE i.id IS NULL
附录:
测试用例(在对选定答案的评论中提供)演示了在子句中使用谓词和在子句中的查询之间结果集items.item_id = 5
的ON
差异WHERE
。(将此谓词移动到 WHERE 子句会与反连接混淆。)
CREATE TABLE `group` (`id` INT PRIMARY KEY, `gid` INT, `mid` INT);
CREATE TABLE `items` (`id` INT PRIMARY KEY, `item_id` INT, `mid` INT);
CREATE TABLE `members` (`id` INT PRIMARY KEY, `email` VARCHAR(40));
INSERT INTO `group` VALUES (1,1,1), (2,1,2);
INSERT INTO `items` VALUES (1,5,1);
INSERT INTO `members` VALUES (1,'one@m.com'),(2,'two@m.com');