CakePHP 2.3でOn Duplicate Key構文を実装
2018/08/04
CakePHPで On Duplicate Key構文を実装
On Duplicate Key構文とは
On Duplicate Key構文とは、Insertしようとした際、Unique項目に重複する値を指定していた場合、Insertせずに Updateを実行するための構文です。
似たような構文として「Replace Into」構文もあります。
※データベースは、MySQLを想定しています。
On Duplicate Key構文については「Insert On Duplicate Key Update構文の使い方」という記事も書いていますので、そちらもご覧ください。
また、この記事は、「CakePHP 2.3 主キー(ID)以外のキーで更新をする方法」の実験を行ったテーブルを続けて利用していますので、もし、サンプルプログラムを実装する際は、こちらの記事を参考にしていただき、テーブルの構築、プログラムの設置を行ってください。
さらに、続きの記事として「CakePHP 2.3で saveの便利な使い方・サンプルソース付き」もありますので参照ください。
また、MySQLのユニークキーには最大バイト数の制限がありますので、そちらは「MySQLのInnoDBでUniqueキーは最大767バイト」の記事をご覧ください。
この記事は、CakePHP2.3での実装方法ですが、CakePHP3での実装方法については、下記の記事を参考にしてください。
CakePHP3で生の SQLの実行はConnectionManagerを使う
On Duplicate Key構文を CakePHPに実装する方法・その1
CakePHPで On Duplicate Key構文を実装する方法は
見つかりませんでした。
どなたか教えてください!
そのため、Queryメソッドを利用して、SQLを直接記述することにしました。
————————
public function edit4($id = null) {
if (!$this->Comment->exists($id)) {
throw new NotFoundException(__('Invalid comment'));
}
if ($this->request->is('post') || $this->request->is('put')) {
$sani_list = "'" . Sanitize::escape( $this->request->data['Comment']['list'] ) . "'";
$sql = "INSERT INTO comments ( post_id, sec_code, list ) values ( {$this->request->data['Comment']['post_id']}, {$this->request->data['Comment']['sec_code']}, {$sani_list} )
ON DUPLICATE KEY UPDATE post_id = {$this->request->data['Comment']['post_id']}, sec_code = {$this->request->data['Comment']['sec_code']}, list = {$sani_list} ";
if ( $this->Comment->query($sql) !== false ) {
$this->Session->setFlash(__('The comment has been saved.' ));
$this->redirect(array('action' => 'index'));
} else {
$this->Session->setFlash(__('The comment could not be saved. Please, try again.' ));
}
} else {
$options = array('conditions' => array('Comment.' . $this->Comment->primaryKey => $id));
$this->request->data = $this->Comment->find('first', $options);
}
}
————————
変更点は、6行目~9行目です。うち、SQL文は 7行目、8行目です。
SQL文はサニタイズする必要があることと、全角文字が入る個所は「’(シングルクォート)」で囲まないとエラーになりますので、6行目でその処理をしています。
9行目も少し変更しています。これは、Queryメソッドの戻り値が「true/false」だけではないためです。
Queryメソッドの戻り値は下記の様になります。
false:SQLにエラーがある場合
array():SQLが正常に処理されたが、値が返ってこなかった場合
取得した値:SQLが正常に処理され、値が返ってきた場合
そのため、今回の様に Select文ではない SQLを実行した場合の戻り値は、正常に終了した場合は「array()」となりますので、上記のサンプルのような if文になっています。
また、SQLに記述する項目の順番は特に気にする必要はないようです。Uniqueキーに設定した項目を先に書く必要もないようです。
また、間違いやすい点としては、7行目、9行目のテーブル名です。
7行目では「comments」と書いていますが、SQL文を直接実行しますので、CakePHPのテーブルの指定と違い実際に存在するテーブルの名称をそのまま記述します。
しかし、9行目の「Comment」の部分は、CakePHPで処理をする部分ですので、CakePHPの規約に従い記述します。
ON DUPLICATE KEY構文を CakePHPに実装する方法・その2
SQL文を直接記述する方法で実装する場合、bind機能を使って実装する方がスマートに実装できます。
エスケープ処理もする必要がありません。
————————
public function edit5($id = null) {
if (!$this->Comment->exists($id)) {
throw new NotFoundException(__('Invalid comment'));
}
if ($this->request->is('post') || $this->request->is('put')) {
$sql = "INSERT INTO comments ( post_id, sec_code, list ) values ( ?, ?, ? )
ON DUPLICATE KEY UPDATE post_id = ?, sec_code = ?, list = ? ";
$post_id = $this->request->data['Comment']['post_id'];
$sec_code = $this->request->data['Comment']['sec_code'];
$list = $this->request->data['Comment']['list'];
if ( $this->Comment->query($sql, array ($post_id,$sec_code,$list,$post_id,$sec_code,$list), false ) !== false ) {
$this->Session->setFlash(__('The comment has been saved.' ));
$this->redirect(array('action' => 'index'));
} else {
$this->Session->setFlash(__('The comment could not be saved. Please, try again.' ));
}
} else {
$options = array('conditions' => array('Comment.' . $this->Comment->primaryKey => $id));
$this->request->data = $this->Comment->find('first', $options);
}
}
————————
戻り値の処理や、テーブル名称の気を付ける点はその1の時と同じです。
11行目の queryで渡している引数の 3つ目は、キャッシュを OFFにするための設定です。デフォルトは ONですので、OFFにしたい場合に記述します。
SQL文の中や、Queryメソッドの処理で引数に配列を与えるところで、「,」の数があっていなかったり、配列の最後に「,」が付いていたりする場合は、エラーの原因になりますので、エラーが出る場合はそんなところも確認してみてください。
この記事を書くにあたっては、下記のサイトを参考にさせていただきました。
CakePHP1系では、CakePHPが処理をする疑似バインド機能だったようですが、CakePHP2系になるとプリペアドステートメント(Prepared Statement)になっているようです。
http://d.hatena.ne.jp/cakephper/20090417/1239939705
http://d.hatena.ne.jp/cakephper/20120204/1328324327
この記事が参考になったと思いましたらソーシャルメディアで共有していただけると嬉しいです!
関連記事
-
-
CakePHP4のクリエビルダーを使用してOR条件をAND条件でつなぐSQL文を作る方法
CakePHP4のクリエビルダーを使って複数のOR条件をANDでつなぐSQL文を作成する方法を解説。OR条件を記述したwhere句を2つつなげて記述する。
-
-
CakePHP 2.3で確認画面付きのお問い合わせフォームの作り方
CakePHPで確認画面付きのお問い合わせフォーム、メールフォームの作り方をサンプルを提示しながら解説。
-
-
CakePHP4、5で$_SERVERと同じようにURIを取得する「getUri()」の紹介
PHPでサーバ情報、環境情報を取得する際は「
$_SERVER」を利用するが、似たような情報をCakePHPの関数で取得する際は「getUri()」を使用する。取得出来る値は一致するものもあるが、違うものもあり便利な使い方もある。
-
-
CakePHP3のCakeDC/Users、Authでログインなしでもアクセスを許可する設定
CakePHP3の Authコンポーネントや CakeDC/Usersプラグインなどを利用したユーザ管理・認証システムにおいて、ログインしていなくても見ることができるページの設定方法を解説。
-
-
CakePHP3でファイルのアップロード処理を自作・解説付き・その1
CakePHP3でファイルをアップロードする処理を、php.netにある「エラーを起こさない」と説明がある処理を参考に作成。サンプルソースとその解説付きで、コピペでも動くし、カスタマイズも簡単!
-
-
CakePHP3、CakePHP4、CakePHP5のバージョンを指定してインストールする詳細な手順を解説
CakePHP3のバージョンを指定してインストールする方法を詳細解説。CakePHP3のインストールはComposerを使うため設定もほぼ自動で完了。データベースの接続情報を記載すればアプリ開発のベースが整う。
-
-
MySQL+CakePHPのdate型、datetime型項目は「2999-12-31」までしか扱えない
CakePHPの日付、日時の型であるdate型、datetime型の最大値は2999-12-31となっている。MySQLは9999年までなので違いがあるので注意が必要だ。
-
-
CakePHPで favicon.icoやapple-touch-icon-144-precomposed.pngが could not be foundのエラーが出るときの対処方法
CakePHPで「CakeDC/Users」などルーティングを行うプラグインを利用するときに、favicon.icoやapple-touch-icon-144-precomposed.pngがNotFoundエラーになることがある。その対処方法の解説。
-
-
CakePHP3にWYSIWYGエディタのCKEditor4を設置、カスタマイズ方法を解説
WYSIWYGエディタであるCKEditor4をCDNを利用して簡単にCakePHP3に導入する方法とカスタマイズする方法を解説。CakePHP3にはページごとの振り分けを行うブロック化を利用する。
-
-
CakePHP4、CakePHP5のメッセージ日本語化の設定(国際化と地域化の機能の使い方の解説)
CakePHP4の英語のメッセージを日本語化(多言語化)する手順を解説。オリジナルのメッセージを作成する方法やプログラムで文言を追加する場合の対応なども解説。