一時的なテーブルは必要ないと思います。許容できるパフォーマンスが得られない場合にのみ、実際にそのルートに進みます。
クエリから、次のようなスキーマを収集します。
group (id INT PK, gid INT, mid INT)
items (id INT PK, item_id INT, mid INT)
members (id INT PK, email VARCHAR)
あなたのテーブルは実際には「メンバーシップ」テーブルのように見えますgroup
。これは、グループと個人の間の多対多の関係を解決/実装します。(つまり、人は0、1つ以上のグループのメンバーになることができます。グループは、ゼロ、またはそれ以上の人をメンバーとして持つことができます。)
group
との間でLEFTJOINを使用していmembers
ます。これにより、一致するメンバーがない場合にグループの行が返され(group.idが返されます)、members.emailにはNULLが返されます(これは必要な場合があります)。ただし、メールアドレスのみを返したい場合は、これをINNERJOINに変更できます。
NOT EXISTS述部は、OUTER JOINと、JOINEDテーブルから返されたNULL値のテストに置き換えることができます。group.gid
および/または列が数値データ型の場合items.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');