Zend_Db_SelectでネストされたSQLを使えるようにする

Zend_Db_SelectでネストされたSQLを使いたい.
つまり,こういうSQLを発行したい.

SELECT * FROM hoge WHERE A = 'xxx' AND (B = 'yyy' OR B = 'zzz');

少し調査をしていたら,そのようなメソッドは提供されていないので,
自分で作らなければいけないという情報を発見した.

なお、以下の様な「()」を利用した条件の設定は出来ません。
SELECT * FROM test WHERE name='hoge' AND (id='1' OR id='2')
現在のZend_Dbでは、このようなメソッドは提供されていないので、
「Zend/Db/Select.php」の「where」、「orWhere」メソッドを拡張、または機能を追加します。


引用元:Zend Frameworkについて(DB編3):なまはげ カンタービレ


自分の手元にある最新バージョン(Select.php 23775 2011-03-01 17:25:24Z)でもやはり提供されていなかった.
いつもなら諦めるけど,今回はどうしても使いたかったのでメソッドを作成することにした.

使い方

<?php
$select->orWhereNest(array(array('B = ?', 'yyy'), array('B = ?', 'zzz'));
?>

生成されるSQL

SELECT * FROM hoge WHERE A = 'xxx' AND (B = 'yyy' OR B = 'zzz');

関数

<?php
// Zend/Db/Select.phpに追記
public function orWhereNest($conditions)
{
    if (!is_array($conditions)) return false;
    $_where = null;
    foreach ($conditions as $condition_key => $condition) {
        $_first_flag = true;
        if ($this->_parts[self::WHERE]) {
            foreach ($condition as $c) {
                if (is_null($c[1])) ? $c[1] = null : '';
                if ($_first_flag) {
                    $_where .= $this->_where(' ( ' . $c[0], $c[1], null, true);
                } else {
                    $_where .= $this->_where($c[0], $c[1], null, false);
                }
                $_first_flag = false;
            }
        }
        else {
            $_where .= ' ( ';
            foreach ($condition as $c) {
                if (!$_first) $_where .= ' OR ';
                if (is_null($c[1])) ? $c[1] = null : '';
                $_where     .= $this->_where($c[0], $c[1], null, false);
                $_first_flag = false;
            }
        }
        $_where .= ' ) ';
    }
    $this->_parts[self::WHERE][] = $_where;

    return $this;
}
?>

対応していること,いないこと

対応してる
  • ネストされたSQLが生成できる.
  • プリペアドステートメントに対応している.
対応していない
  • ネストされた中での[AND|OR]の判別してない.必ずORになる.
  • 前に条件がある場合は必ず、AND (〜)という形式になる.

※今回はそこまで必要なかったので作成していないですが,上の関数をいじれば簡単に出来るかと思います.
使いたい方がいらっしゃったら,ご自由にお使いください(責任は取れませんが…).


という感じで,無事に使えるようになりました.