PHPでユニーク制約カラムへの登録はIGNOREを使うとスムーズ[MySQLエラーコード23000]
ユニーク制約とは、重複した値を登録することができないことを意味します。
たとえば1000件のデータを作る場合、1件ずつ重複チェックをしてから登録という流れになると思います。
テーブルロックしないと他から登録されたり、1000件の作成データ内にも重複がないかチェックしたりと結構面倒だったりします。
そこでスムーズな登録処理方法の1つとして、ユニーク制約のあるテーブルへの連続登録PHPプログラムをご紹介します。
対象のカラムがユニーク制約である前提です。
MySQLのエラーコード23000
ユニーク制約のかかったカラムに、登録されている値と同じ値を登録してみます。
すると、以下のようなエラーが返ってきます。
SQLSTATE[23000]: Integrity constraint violation Duplicate entry
「重複した値を登録しようとしたよ」というエラーです。
PHPではこの23000エラーを判定して登録処理を行います。
エラーコードを判断して連続登録
ユニーク規約カラム「コード」に乱数文字列を生成して1000件登録するサンプルコードです。
<?php // データベースに接続 $pdo = new PDO( 'mysql:dbname=table;host=127.0.0.1;charset=utf8', 'user', 'pass', [ PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION, PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC, ] ); //保存できた件数 $saved_count =0; //1000件登録したいとする while ($insert_count < 1000) { //3文字のランダム英数字を生成する $code = substr(str_shuffle('1234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'), 0, 3); try { //トランザクション開始 $pdo->beginTransaction(); //INSERTクエリ $insert_sql = "INSERT INTO t_code (code, created) VALUES (:code, CURRENT_TIMESTAMP)"; $stmt = $pdo->prepare($insert_sql); $stmt->bindParam(':code', $code, PDO::PARAM_STR); //実行 $flg = $stmt->execute(); //コミット $pdo->commit(); //登録成功件数をカウント $insert_count++; } catch (PDOException $pdo_ex) { //ロールバック $this->rollback(); //エラーコード重複登録はスキップ if ($pdo_ex->getCode() == 23000) continue; //重複登録以外エラー //終了orスキップなどの処理を入れる } }
ポイントは
・whileを使い1000件登録するまでループする
・トランザクションを用いる
・PDOExceptionを使い、重複登録時には例外をキャッチする
・キャッチしたエラーコードを見て(23000だったら)スキップする
の4つ。
これで1000件のユニークなデータを登録することができます。
エラーを発生させずに終了するIGNORE
MySQLにはIGNOREという便利な機能も存在します。
登録時に失敗してもスルーしてくれます。
ユニーク制約カラムであれば、重複データの登録は行わずに終了します。
なので特に気にせずにガンガンデータを作って登録ができるのです。
そうなると1000件分(希望の件数)登録できたかどうかを判定する方法が必要です。
INSERT IGNORE INTOを使って連続登録
先ほどのサンプルソースを基本としてINSERT IGNORE INTOを使ってコードを書いてみます。
<?php //トランザクション開始 $pdo->beginTransaction(); //INSERTクエリ $insert_sql = "INSERT IGNORE INTO t_code (code, created) VALUES (:code, CURRENT_TIMESTAMP)"; $stmt = $pdo->prepare($insert_sql); $stmt->bindParam(':code', $code, PDO::PARAM_STR); //実行 $flg = $stmt->execute(); //変更できたレコード数を取得 $res_count = $stmt->rowCount(); if ($res_count > 0) { //コミット $pdo->commit(); //登録成功件数をカウント $insert_count++; }
$stmt->rowCount();
変更できたレコード数を取得し、0件以上のレコードが更新されていればコミットするようなロジックです。
どちらの方法もSELECTして件数を見る必要がなく、どんどん登録していくので効率良く処理ができます。