テーブルからデータを削除するときは、DELETE文を使用します。
DELETE文は、SELECT文やUPDATE文、INSERTと比較して一見、地味な存在です。データを削除するときは、そのテーブルの持つ主キーを指定して消すことが多いので、あまり複雑にはならないからです。
ですが、DELETE文もINSERT文やUPDATE文に負けないくらい多彩な表現が可能です。単に主キーの値を指定して削除するだけではなく、DELETE文をもっと活用してみましょう!
本記事ではDELETE文の基本構文から始まり、サブクエリやテーブル結合を活用したDELETE文、DELETE文におけるアンチパターンまで解説します。
※また、本記事に出てくるSQLは、MySQLを使って動作検証をしています。SQLの前には、そのSQLの仕様(何をどこへ登録したいのか)を書いておりますので、仕様とSQLを比べて見て理解を深めてください。
まずはDELETE文の基本からです。
DELETE対象が全レコード(全削除)
DELETE文の一番シンプルな例、テーブルのデータをすべて削除するSQLです。
簡単ですね。DELETE FROMのあとにテーブル名を書くだけです。
ただし、テーブル内の全データを削除するというケースはあまりありません。あったとしても本当に全データを削除するのなら、後に出てくるTRUNCATEを使います。
データを限定して削除したいときは、WHERE句で絞り込み条件を指定します。
DELETE対象を限定する(WHERE)
特定のデータだけを削除するときは、WHERE句を使って対象を絞り込みます。SELECT文で使用するWHERE句と考え方は同じです。
テーブルの主キーを指定して削除する方法です。
仕様:テーブルのデータを、主キー値指定で削除する
もう少し具体的に解説します。
例えばユーザ(users)というテーブルがあったとします。ユーザのようなテーブルは、一般的に名称が「ID」のような項目を設けて、登録されるごとにIDに連番を付与していきます。よって10番目に登録されるユーザのIDは10になります。このユーザを削除する場合、こうなります。
仕様:テーブルusersの、IDが10のデータを削除する
もちろんWHERE句の中は主キーだけでなく、それ以外の項目を使って記述できます。例えばusersというテーブルの、名前(name)が 'user01' というデータだけ削除したい場合は以下のようになります。
仕様:テーブルusersの、カラムnameがuser01というデータだけ削除する。
もうお気づきかと思いますが、SELECT文と同じノリでLIKE句も使えます。
仕様:テーブルusersの、カラムnameがuserで始まるデータだけ削除する。
DELETE対象を限定する(上位または下位##件)
DELETE文は、ORDER BYと併用できます。
ORDER BYを使って、主キーが5以降のユーザを消しましょう。
仕様:テーブルusersの、IDが5以降を削除する
(注)IDが主キーの場合は、何もしなくてもIDの昇順で並ぶので、ORDER BYは厳密には不要です。
その他、LIMITを使って件数を絞ることもできます。例えばテーブルusersの主キーを降順に並べて上位3件を指定する場合はこうなります。
仕様:テーブルusersの、IDの降順に並べて上位3件を削除する
IDの降順に並べて上位3件、というと複雑に聞こえますね。簡単にいうと末尾3件です。DESCをASCに書き換えれば、昇順に並べて上位3件を削除することができます。
DELETE文の応用
DELETE文を使った応用的なSQLを見ていきましょう。先ほどDELETE文のWHERE句の使い方はSELECT文のWHERE句と同じと解説しました。
ここではサブクエリと結合を使ったDELETE文を解説します。
DELETEにサブクエリを使用
ちょっと復習しましょう。サブクエリとは何でしょうか?
サブクエリとは、むずかしい定義はさておいて、要はSQLの中にSQLがあると思ってください。例えば、平均点以下の生徒を削除するには(残酷な例ですが)こうなります。
まずは平均点以下の生徒を抽出しましょう。生徒はusers、点数はscoresというテーブルに格納されているとします。
仕様:テーブルscoresの、点数scoreが平均点以上の生徒を算出する。
あとはこれをWHERE句に入れてあげれば、サブクエリを含んだSELECT文ができます。
仕様:テーブルusersにおいて、平均点以下の生徒を抽出する。
ここまできたら、あと一息です!
SELECT * をDELETE に置き換えましょう。
仕様:平均点以下の生徒を削除する
これでサブクエリを使ったDELETE文ができました!
結合(JOIN)を使ったDELETE文
SQLにはJOINという、テーブルを結合させるコマンドがあります。ではこれを用いて、複数テーブルを同時に削除したいと思いませんか?
MySQLでは、JOINを使って複数テーブルから同時にデータを削除できます。
※「MySQLでは」と明記したのは、データベースによってDELETE文でテーブル結合が使えたり使えなかったりするためです。本記事ではMySQLを使いましたが、異なるデータベースを使うときは、そのデータベースがDELETE文でテーブル結合を使えるかどうか、あらかじめ十分に調べてください。
table1, table2, table3 という3つのテーブルがあり、それぞれにidというカラムがあったとします。この3つのテーブルに共通するidのデータは、このように抽出します。
仕様:table1, table2, table3という3つのテーブルに共通するデータを抽出する
ではさっそく、SELECT * をDELETEに変えてみましょう。
仕様:table1, table2, table3という3つのテーブルに共通するデータを削除する??
残念ながら、今回はそうはいきません。最初に出てくるINNERのところで、このエラーが出ます。
"INNER" is not valid at this position
しかしこの「エラーが出る理由」が絶妙な使い心地を発揮します。まずは完成形をお見せします。
仕様:table1, table2, table3という3つのテーブルに共通するデータを削除する!
FROM句の前に、削除する対象のテーブルを書かなくてはなりません。言い方を変えると、FROMの前に書いていないテーブル名は、結合条件には使われますが消えません。
これを応用すると、3テーブルに共通するレコードを、table1だけ削除するという器用なことができるのです!
仕様:table1, table2, table3という3つのテーブルに共通するデータを、
table1だけ削除する
DELETE文のアンチパターン
今まで出てきたDELETE文ですが、いろいろと注意すべきアンチパターンがあります。順に見ていきましょう。
DELETE文で全件削除
DELETE文を使ってデータを完全削除する場合、TRUNCATEの利用も検討しましょう。
データの件数が少ないうちは、DELETE文とTRUNCATE文の速度差は感じられません。ところが件数が多くなると、その差は圧倒的です。
DELETEはROLLBACKに備えてUNDO領域に・・・、COMMITで・・・、と説明すべきですが、それは他のサイトにお任せします。「DELETE TRUNCATE 違い」でググってみてください。
要は「DELETEはもとに戻すことを想定していろいろと処理が動く、しかしTRUNCATEはそれらをせずにバッサリ消す」「DELETEはCOMMITするまでに戻せるが、TRUNCATEは戻せない」とご理解ください。
全件削除する場合、DELETEとTRUNCATEの比較をして、用途に合ったものを選択することをオススメします。
WHERE句の間違いで地獄を見る
DELETE文を実装・実行する際は、必ずSELECT文で削除対象を確認してからにしてください。今まで解説してきたように、SELECT * をDELETE FROMで置き換えれば大半のケースでは対応できます。もっというと、SELECT文を作ってからDELETE文に書き換えてもいいくらいです。
ということはDELETE文において、そもそもSELECT文の段階で間違っていると、当然想定していないデータが削除されます。WHERE句の間違いで全件指定になっていると・・・いうまでもなく全件削除になります。
しかも対象のテーブルに大量にデータが入っていた場合、実行中に誤りに気づいたものの、クライアントツールで実行のキャンセル中にツールがフリーズしてしまい、あとは全件削除が完了するのを待つ間、始末書の準備をするしかないという地獄を見ます。
DELETE文の実行前には、必ずSELECT文で削除対象を確認しましょう。
論理削除と物理削除の違い
DELETE文のアンチパターンというより、どちらかというと設計よりの話です。昔から「論理削除か物理削除か」という壮絶なバトル論争が続いています。
論理削除とは、テーブルからデータを削除せずに、「削除フラグ」といった項目に削除済みです、というマークをつけます(大半は論理値でtrueなら現存、falseなら削除済みとします)。
物理削除とは、本当にテーブルからデータを削除してしまいます。
論理削除ならかんたんに復活できるけど物理削除ならそれができない、いやいや論理削除は大量の削除済みデータを残すことになりレスポンスが低下、と一長一短です。もしデータベースの設計を任されるようになったら、この問題に取り組んでみてください。
まとめ
本記事ではDELETE文を解説しました。
効率的なDELETE文が書けるよう、本記事に出てきたSQLをぜひご自身でも動かして結果を確認してみてくださいね!
- カテゴリ: