PreparedなINSERT文を簡単に作る方法

PHPでWebアプリケーションなどを開発していて、SQL文を発行する際に、セキュア面や利便性などから、ADODBPDOなどを用いて、Prepared Statementを使うSQLを書くこともあると思います。

その際、特にINSERT文などはカラムの数だけVALUESの中に ? が並ぶことになるかと思います。


SQL:
  1. -- 例:
  2. INSERT INTO
  3. `persons` (`id`, `name`, 'age`, `birthday`, `mailaddress`, `phone`, `zipcode`, `address`)
  4. VALUES (?, ?, ?, ?, ?, ?, ?, ?);



このとき、 ? がひたすら並んでいるだけとなると非常に見づらく、INSERTする情報が多くなってくると、指定したカラム数と VALUESの ? の数が一致せず、

Number of variables doesn't match number of parameters in prepared statement

といったエラーに遭遇したことが一度はあるかと思います。
特に、プログラムの改修をする際などは、カラム名だけ追加して、うっかり VALUESの ? だけ追加のし忘れなどをしてしまうことなんかも。。。

そこで、Prepared Statementを作る際のINSERT文のSQLを簡単で分かりやすくしたいと思います。


PHP:
  1. <?php
  2. $dsn = 'mysql:dbname=testdb;host=127.0.0.1';
  3. $user = 'dbuser';
  4. $password = 'dbpass';
  5.  
  6. try {
  7.     $db = new PDO($dsn, $user, $password);
  8.    
  9.     // INSET対象となるカラム名を指定
  10.     $columns = array(
  11.         'id',
  12.         'name',
  13.         'age',
  14.         'birthday',
  15.         'mailaddress',
  16.         'phone',
  17.         'zipcode',
  18.         'address',
  19.     );
  20.    
  21.     $binds = array(
  22.         1   => 'anon',
  23.         2   => 'anon',
  24.         3   => '25',
  25.         4   => '1984-05-02',
  26.         5   => 'root@example.com',
  27.         6   => '03-xxxx-xxxx',
  28.         7   => 'xxxxxx',
  29.         8   => 'Tokyo',
  30.     );
  31.    
  32.     $sql = 'INSERT INTO persons '
  33.          . implode(', ', $columns)
  34.          . ') VALUES ('
  35.          . implode(', ', array_fill(0, count($columns), '?'))
  36.          . ')'
  37.          ;
  38.    
  39.     /*
  40.     // またはテーブル名やカラム名を明示的にクオートする場合はこちら
  41.     $sql = 'INSERT INTO `persons` '
  42.          . '`' . implode('`, `', $columns) . '`'
  43.          . ') VALUES ('
  44.          . implode(', ', array_fill(0, count($columns), '?'))
  45.          ;
  46.     */
  47.    
  48.     $stmt = $db->prepare($sql);
  49.    
  50.     foreach($binds as $key => $value){
  51.         $stmt->bindValue($key, $value);
  52.     }
  53.    
  54.     return $stmt->execute();
  55.    
  56. } catch (Exception $e) {
  57.     error_log('[' . get_class($e) . '] ' . $e->getMessage() . ' in ' . $e->getFile() . ' on line ' . $e->getLine());
  58. }



要点は、 $columnsという配列にカラム名を配列で持たせ、Prepared INSERT文を発行する際に、implode()関数でそのカラム名をカンマ区切りで連結、VALUESの ? は array_fill()関数で、カラム名の配列の値の数だけ ? で埋めた配列を作成し、さらにそれをimplode()関数で連結していく。

というだけです。

バインドの個所は今回手抜きにしてしまいました。
本当はバインドも同じようにもう少し見直せばもっと分かりやすく、簡潔にできると思うのですが、
いい書き方が浮かびませんでした。。。

No TweetBacks yet. (Be the first to Tweet this post)

Related posts:

  1. PHPで相対パスから絶対URL(URI)を作成する HTMLページをパースしてURLを取り出す処理を書いていたのですが、ページ内のリンクなどが全部絶対URLで記述されていれば非常に楽なのですが、現実としてそうでもなく、ページによっては相対パスで書かれていたりして、正規表 [...]...

関連記事はYARPP関連記事プラグインによって表示されています。

Leave a Reply

Get Adobe Flash playerPlugin by wpburn.com wordpress themes