読者です 読者をやめる 読者になる 読者になる

FuelPHP で複数の OR 条件を使う SQL を書く

FuelPHP で複数の OR 条件を書く場合,Query Builder を使う必要があって,ORM だと実現できなかった.検証環境は FuelPHP 1.6 で,もしかしたら FuelPHP 1.7 以降で修正されているかもしれないけど,調べてる限りだとできなさそう.

前提

SQL に特に意味は無くて,単純に外側で2回 OR 条件を連結する例で考える.

Query Builder

Orm\Model

or_where_open()or_where_close() で囲って書いた.

return Model_User::query()
    ->or_where_open()
    ->where('id', '=', 1)
    ->or_where_close()
    ->or_where_open()
    ->where('id', '=', 2)
    ->where('type', '=', 2)
    ->or_where_close()
    ->or_where_open()
    ->where('id', '=', 3)
    ->where('type', '=', 3)
    ->or_where_close()
    ->from_cache(false)
    ->get();

以下の SQL が生成される.

SELECT
    *
FROM
    `users` AS `t0`
WHERE
    (
        `t0`.`id` = 1
    ) OR
    (
        `t0`.`id` = 2 AND
        `t0`.`type` = 2
    ) OR
    (
        `t0`.`id` = 3 AND
        `t0`.`type` = 3
    )

Orm\Model_Soft

Orm\Model_Soft を継承している場合,自動的に論理削除条件が入るため,1回目を and_where_open()and_where_close() で囲う必要がある.

return Model_User::query()
    ->and_where_open()
    ->where('id', '=', 1)
    ->and_where_close()
    ->or_where_open()
    ->where('id', '=', 2)
    ->where('type', '=', 2)
    ->or_where_close()
    ->or_where_open()
    ->where('id', '=', 3)
    ->where('type', '=', 3)
    ->or_where_close()
    ->from_cache(false)
    ->get();

以下の SQL が生成される.

SELECT
    *
FROM
    `users` AS `t0`
WHERE
    `t0`.`deleted_at` IS null AND
    (
        `t0`.`id` = 1
    ) OR
    (
        `t0`.`id` = 2 AND
        `t0`.`type` = 2
    ) OR
    (
        `t0`.`id` = 3 AND
        `t0`.`type` = 3
    )

ORM

ORM だと生成される SQL が期待してるものと異なってしまう.具体的には or キーが重複しているため,上書きされて最後の条件だけが残る.どうやるんだろう.調べたけどできなさそうだった.core を修正して or1or2 など拡張したキーを許容させることはできそうだけど,別に Query Builder で良いじゃん!という結論に落ち着いた.

return Model_User::find('all', array(
    'where'      => array(
        array('id', '=', 1),
        'or' => array(
            array(
                array('id', '=', 2),
                array('type', '=', 2)
            )
        ),
        'or' => array(
            array(
                array('id', '=', 3),
                array('type', '=', 3)
            )
        )
    ),
    'from_cache' => false,
));

ダメだ...!

SELECT
    *
FROM
    `users` AS `t0`
WHERE
    `t0`.`id` = 1 AND
    `t0`.`deleted_at` IS null OR
    (
        (
            (
                `t0`.`id` = 3 AND
                `t0`.`type` = 3
            )
        )
    )

関連記事