DB Fiddleで動かす
概要
CREATE TABLE users (
id INT NOT NULL PRIMARY KEY,
name VARCHAR(100),
date_of_birth DATE
);
CREATE TABLE clubs (
user_id INT NOT NULL PRIMARY KEY,
name VARCHAR(100)
);
-- ユーザ
INSERT INTO users VALUES
(1, "Akita", "1985-01-01"),
(2, "Inoue", "1986-01-01"),
(3, "Ueda", "1987-01-01"),
(4, "Endou", "1988-01-01"),
(5, "Okada", "1989-01-01")
;
-- 所属クラブ
INSERT INTO clubs VALUES
(1, "soccer"),
(2, "baseball"),
(5, "tennis")
;
上のようなテーブルとレコードがあって、「クラブに所属していて誕生日が1988/01/01よりも前のユーザとその所属クラブのレコード」を削除したいとき、どうすべきかを考える必要がありました。
(もちろん実際には全然違う話でしたが、2つのテーブルからそれぞれ削除条件を考えて削除しなければいけないケースがありました)
最初は以下のように
-- 所属クラブを削除
DELETE c
FROM clubs AS c
INNER JOIN users AS u ON c.user_id = u.id AND u.date_of_birth < "1988-01-01";
-- ユーザを削除
DELETE u
FROM users AS u
INNER JOIN clubs AS c ON u.id = c.user_id
WHERE u.date_of_birth < "1988-01-01";
それぞれ別にDELETEしようとしましたが、当然これでは意図した通りに削除されません。
先にDELETEをかけているclubsテーブルは意図した通りに削除されますが、usersテーブルでは既にclubsテーブルが削除されてしまっているのでクラブに所属しているという条件で絞り込めなくなっています。
users
| id | name | date_of_birth |
|---|---|---|
| 1 | Akita | 1985-01-01 |
| 2 | Inoue | 1986-01-01 |
| 3 | Ueda | 1987-01-01 |
| 4 | Endou | 1988-01-01 |
| 5 | Okada | 1989-01-01 |
clubs
| user_id | name |
|---|---|
| 5 | tennis |
逆にusersテーブルから削除しようとすると、今度はclubsテーブルのレコードが削除されなくなってしまいます。
users
| id | name | date_of_birth |
|---|---|---|
| 3 | Ueda | 1987-01-01 |
| 4 | Endou | 1988-01-01 |
| 5 | Okada | 1989-01-01 |
clubs
| user_id | name |
|---|---|
| 1 | soccer |
| 2 | baseball |
| 5 | tennis |
同時に2つのテーブルをDELETEするという発想がなかったので、自分はここで恐ろしく悩む羽目になりました。
実際にはただ以下のようにすればよかっただけでした。
DELETE u, c
FROM users AS u
INNER JOIN clubs AS c ON u.id = c.user_id
WHERE u.date_of_birth < "1988-01-01";
このクエリであれば意図した結果が得られます。
users
| id | name | date_of_birth |
|---|---|---|
| 3 | Ueda | 1987-01-01 |
| 4 | Endou | 1988-01-01 |
| 5 | Okada | 1989-01-01 |
clubs
| user_id | name |
|---|---|
| 5 | tennis |
そもそも...
MySQLであれば公式のドキュメントに記載があった。
複数テーブルの削除