PHPでデータベース(MySQL)を操作ってよくやりますよね。そして、データベースを操作する中でレコードの削除もよく行うと思います。
レコードの削除はDELETEを使えばいいわけですが、ここで私がハマったのが、DELETE文で削除したときに対象のレコードがなかったとしても削除されたと認識されることです。
今回はこの内容の説明と対策を紹介します。
PHPでのDELETE文の作り方
例えばこんなデータベースのテーブルがあったとします。
データベース名:testdb、テーブル名:testtbl
No | name |
1 | 太郎 |
2 | 次郎 |
3 | 三郎 |
このテーブルのNoの番号が入力されたら、そのレコードを削除したいとします。
まずは、Noの番号を入力する画面をHTMLなどで作ります。
1 2 3 4 5 |
<!--ファイル名:input.html--> <form method="post" action="delete.php"> <input type="input" name="No"> <input class="submit_button" type="submit" value="削除"> </form> |
これで入力欄に値を入力し、”削除”のボタンを押すと、”delete.php”が動きます。
次に、PHPでDELETE文を作ってみましょう。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
/*ファイル名:delete.php */ //input.htmlの入力内容を変数numに入れる $num = trim($_POST["No"]); //DBへの接続設定 $user = 'tester'; //ユーザー名 $password = 'password'; //パスワード $dbName = 'testdb'; //接続するDB名 $host = 'mysql0000.xxxxx.jp'; //接続するホスト名 $dsn = "mysql:host={$host};dbname={$dbName};charset=utf8"; //接続内容 //データベースに接続する $pdo = new PDO($dsn, $user, $password); //プリペアドステーメントのエミュレーションを無効にする $pdo->setAttribute(PDO::ATTR_EMULATE_PREPARES, false); //例外がスローされる設定にする $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); //SQL文 $sql = 'DELETE FROM testtbl WHERE No=:num'; //プレペアドステートメントを作る $stm = $pdo->prepare($sql); //プレースホルダに値をバインドする $stm->bindValue(':num', $num, PDO::PARAM_STR); //SQLを実行する $stm->execute(); //削除したNoを表示する echo '<p><span class="error">No.'.$num.'を削除しました。</span></p>'."\n"; |
(ユーザ名:tester、パスワード:password、接続するホスト名:mysql0000.xxxxx.jp としました。)
このようなdelete.phpを作った上で、input.htmlで入力欄に値を入力し削除ボタンを押すと、入力された値のNoのレコードが削除されます。
例えば、input.htmlで1を入力し、削除ボタンを押したとします。
すると、このように表示され、
testtblは、このようになります。
No | name |
2 | 次郎 |
3 | 三郎 |
これが基本的なDELETE文の作り方です。
※本当は例外処理なども入れるべきですが今回は省いています。
もしテーブルにないNoを入力したらどうなる?
では、input.htmlで4などのテーブルのNoにない値を入力し、削除ボタンを押したらどうなるでしょうか?
ちなみに、私はエラーが出て、例外処理で拾えばいいと考えていました。結果は
はい???いやいや、ちょ、待てよ
Noが4のレコードがないにも関わらず、実行されてしまうんです。
MySQLなどを触ったことがあるとわかるのですが、DELETE文を実行した際、対象のレコードがない場合でも「0行を削除しました。」となり、エラーにはならないんですよね…(知らなかった)
rowCount() を使って戻り値を取得する
これで何が困るかって、削除したはずなのに消えていない!、不具合だ!と騒がれること。(まあ見た目もアウトですが…)
ということで、対策を考えます。
考えたのは何件削除されたのかがわかれば、テーブルからレコードが削除されたかどうかがわかるはずというもの。
PDOStatement->rowCount() — 直近の SQL ステートメントによって作用した行数を返す
を使います。
SQLを実行した後に
1 2 3 4 5 6 7 8 9 |
/*$stm->execute(); の後に追加*/ //削除した行数を取得 $cnt = $stm->rowCount(); //削除した行数が1以上なら削除成功、0なら削除できる番号がないとみなす if($cnt>=1){ echo '<p><span class="error">No.'.$num.'を削除しました。</span></p>'."\n"; }else{ echo '<p><span class="error">No.'.$num.'は存在しません。番号を確認してください。</span></p>'."\n"; } |
を追加し、再度4を入力し、削除ボタンを押すと、
と表示が変わりました。
やった~!!!
ちなみに私はDELETE文で削除した際、対象となるレコードが無くてもエラーにならないことを知らず、永遠と悩んでいました…。
もし私と同じように、DELETE文のエラーが出ない!と悩んでいたら、rowCount()を使い、削除件数の戻り値を取得するとうまくいきますよ。