SQL DELETE徹底比較:MySQL・PostgreSQL・SQL Serverでどう書く?
目次
DELETE文はデータ削除というシンプルな操作でありながら、JOINの扱い・返り値・行数制御・制約チェックなど、RDBMSごとにじわっとクセが出る領域。
ここでは MySQL・PostgreSQL・SQL Server を横並びにして、違いを整理していく。
基本のDELETE構文はほぼ共通
最も基本的なDELETE文はどのDBでもそのまま動く。
DELETE FROM users
WHERE id = 1;
このレベルは3製品とも大差なし。ただし、削除対象の行数制御やJOINを使うかどうかで違いが出始める。
JOIN付きDELETEの構文差
DELETEにJOINを絡めたいシーンは現場で意外と多い。ここが3製品で最も違う部分。
MySQL(DELETEに直接JOINが書ける)
DELETE u
FROM users u
JOIN orders o ON u.id = o.user_id
WHERE o.amount > 1000;
PostgreSQL(USING句を使う)
DELETE FROM users u
USING orders o
WHERE u.id = o.user_id
AND o.amount > 1000;
SQL Server(FROM句でJOIN)
DELETE u
FROM users u
JOIN orders o ON u.id = o.user_id
WHERE o.amount > 1000;
ややこしいが、MySQLとSQL Serverは似た書き方で、PostgreSQLはUSINGを使う。
削除された行を返す仕組み(RETURNING / OUTPUT)
UPDATE・INSERT同様、DELETE後の値を返したいケースは実務で多い。
MySQL
8.0.16以降で限定的にDELETE ... RETURNINGが利用可能。
DELETE FROM users
WHERE id = 1
RETURNING id, name;
PostgreSQL
RETURNINGがフル対応で非常に使いやすい。
DELETE FROM users
WHERE id = 1
RETURNING id, name;
SQL Server
OUTPUT句で対応。
DELETE FROM users
OUTPUT deleted.id, deleted.name
WHERE id = 1;
削除前の値が欲しいなら、deleted.が使えるSQL Serverは特に便利。
LIMIT / TOP による行数制御
DELETEで行数を制限する場合は、DBごとに構文が大きく異なる。
MySQL(LIMITが使える)
DELETE FROM logs
ORDER BY created_at
LIMIT 100;
PostgreSQL(DELETEにLIMITは不可)
サブクエリで代替する必要がある。
DELETE FROM logs
WHERE id IN (
SELECT id FROM logs
ORDER BY created_at
LIMIT 100
);
SQL Server(TOPが使える)
DELETE TOP (100) FROM logs
WHERE status = 'old';
トランザクションと制約の動作差
MySQL
- 外部キー制約はInnoDBで有効
- ON DELETE CASCADEは一般的
PostgreSQL
- 制約の扱いが厳格で標準SQL寄り
- ON DELETE CASCADEも柔軟
SQL Server
- CASCADEルールが豊富
- OUTPUT句と組み合わせる際はトランザクション管理が重要
正規表現を使ったDELETE
MySQL
DELETE FROM users
WHERE name REGEXP '^A';
PostgreSQL
DELETE FROM users
WHERE name ~ '^A';
SQL Server
正規表現が標準サポートされないため、LIKEで代替する必要がある。
削除の戻り値としての行数
3製品とも「削除された行数」はクライアントレイヤーで取得可能。
ただし、SQLそのものに標準化された方法はないため、RETURNING/OUTPUTで値を返す方法が最も確実。
まとめ
DELETE文は基本形こそ共通しているものの、次のポイントで差が大きく出る。
- JOIN付きDELETEの構文
- RETURNING / OUTPUT の扱い
- LIMIT / TOP による行数制御
- 正規表現の可否
- 制約とトランザクション周りの細かな挙動
特にJOINと行数制御はDBごとの癖が強いため、マルチDB環境では書き換えポイントとして意識しておくと安全。
基本構文比較
| 項目 | MySQL | PostgreSQL | SQL Server |
|---|---|---|---|
| 基本DELETE構文 | 共通 | 共通 | 共通 |
| WHERE句 | 共通 | 共通 | 共通 |
| サブクエリ | 共通 | 共通 | 共通 |
| 外部キー制約 | InnoDBで有効 | 標準SQL準拠で厳格 | 柔軟だが動作特徴あり |
JOINを使ったDELETE
| 内容 | MySQL | PostgreSQL | SQL Server |
|---|---|---|---|
| JOINの書き方 | DELETE ... FROM ... JOIN | DELETE ... USING | DELETE ... FROM ... JOIN |
| JOIN例 | DELETE u FROM users u JOIN o | DELETE FROM u USING o | DELETE u FROM users u JOIN o |
| マルチテーブルDELETE | 対応 | 非対応 | 非対応 |
RETURNING / OUTPUT の対応
| DB | 削除後の行を返す方法 | 例 |
|---|---|---|
| MySQL | DELETE ... RETURNING(8.0.16+) | DELETE ... RETURNING id |
| PostgreSQL | RETURNING全面対応 | DELETE ... RETURNING id |
| SQL Server | OUTPUT句 | DELETE ... OUTPUT deleted.id |
行数制御(LIMIT / TOP)
| DB | 行数制御方法 | 例 |
|---|---|---|
| MySQL | LIMIT | DELETE ... LIMIT 100 |
| PostgreSQL | 非対応(サブクエリ使用) | WHERE id IN (SELECT id ... LIMIT 100) |
| SQL Server | TOP | DELETE TOP (100) FROM ... |
正規表現によるDELETE
| DB | 正規表現サポート | 構文 |
|---|---|---|
| MySQL | 対応 | REGEXP |
| PostgreSQL | 対応 | ~ |
| SQL Server | 非対応 | LIKEで代替 |
日付関連の削除条件の違い(代表例)
| 操作 | MySQL | PostgreSQL | SQL Server |
|---|---|---|---|
| 現在日時取得 | NOW() | NOW() | GETDATE() |
| 日付比較の例 | created_at < NOW() | 同左 | 同左 |
DELETE自体に直接差はないが、条件式で関数が異なる点は注意。
特徴まとめ
| 特徴 | MySQL | PostgreSQL | SQL Server |
|---|---|---|---|
| JOIN付きDELETEの書きやすさ | 高い | 標準寄り(USING) | 高い |
| RETURNING(削除行返却) | 限定的 | 最強 | OUTPUTで対応 |
| 行数制御 | 簡単 | 手間 | 簡単 |
| 正規表現条件 | 対応 | 対応 | 非対応 |
| 標準SQL準拠度 | 中 | 高 | 中 |
| ▲ | phpMyAdminでcount(): Parameter must be an array or an object that implements Countable |
| sect: Teches | lastmod: 2018-11-17 | pv: 20 | |