CASE式で変数の値を使おうとしたら詰まりました。
Laravelクエリビルダーむずい。

例えば下記のようにCASE式で変数の値を使用したい場合は、setBindingsを使います。
まず、このsetBindingsを使うというあたり(というかsetBindingsそのものの記述が)公式ドキュメントにないんだよな~

1
2
3
4
5
6
7
8
9
$notDeleted = '未削除';
$deleted = '削除';

->select([
DB::raw(' CASE WHEN detleted_at IS NOT NULL THEN :not_deleted ELSE :deleted END as "deleted_at" ')
->setBindings([
'not_deleted' => $notDeleted,
'deleted' => $deleted ,
]);

で、これを実行すると…
下記のようなエラーが出てうまくいきません。

1
SQLSTATE[HY093]:Invalid parameter number: mixed named and positional parameters

これは「疑問符プレースホルダーと名前付きプレースホルダーを混在して使えません」というエラーです。

Laravelはデータベース接続時にPDOを使用しています。
PDO接続では?を使う疑問符プレースホルダーと:を使う名前付きプレースホルダーの2種類でバインドできます。
この辺りは下記の記事がかなり詳しいです。

PHPでデータベースに接続するときのまとめ

要するにLaravelでは内部で「疑問符プレースホルダー」を使っているっぽく、「名前付きプレースホルダー」をは使えません。
こちらの掲示板で使えないって書いてありました。

Laravel doesn’t let you use named bindings, just use simple placeholders ?:

ですので、「疑問符プレースホルダー」を使って書き直します。

1
2
3
4
5
6
7
8
9
$notDeleted = '未削除';
$deleted = '削除';

->select([
DB::raw(' CASE WHEN detleted_at IS NOT NULL THEN ? ELSE ? END as "deleted_at" ')
->setBindings([
$notDeleted,
$deleted ,
]);

setBindingsで記述した順番で順に?に値がバインドされます。
なお、キーを指定することで順序を変えることができる(?)ようですが、試したところ変わりませんでした…Laravelだと無理なのかな?

StackOverflowでも名前付きプレースホルダーを使えばいいという回答がけっこうあって、この人たちLaravel使ってないだろと思いました。