## 問題の要約

PHPを使って，次のようなものを作ろうとしています．

  * 入力フォームでユーザからの入力を受け付ける．
  * データベースから，ユーザからの入力に合致するようなデータをSQLで取り出す
  * 取り出したデータをPHPで表示する

より具体的に言うと，`Customers`というテーブルがあって，そこに`requestID`というカラムがあります．ユーザが入力フォームから検索して，あるrequestIDを持つようなレコードがあるかどうか検索することができるようにしたいです．

そこで，SQL文をどのようにするかで困っています．

プレースホルダを使って

```

        SELECT 
            * 
        FROM 
            Customers
        WHERE 
            requestID = :requestID
    
```

というSQLを実行し，PHP側で

```

        $sth = $dbh->prepare($sql);
        $sth->bindParam('requestID', $_POST['requestID'], PDO::PARAM_STR);
        $sth->execute();
    
```

という処理を行うことを最初は検討しましたが，これだとユーザ入力が空の時に「requestIDが空であるようなレコード」が検索されてしまいます．

ユーザ入力が空だったときには，「絞り込みは行わない」というふうにしたいです．

まずCASE文とヒアドキュメントを使って，次のようなSQLを書いてみました．

```

        $sql = <<<SQL
        SELECT 
            * 
        FROM 
            Customers
        WHERE 
            requestID = 
            CASE
                WHEN :requestID = '' THEN
                    requestID
                ELSE
                    :requestID
            END
        SQL;
    
```

これならユーザ入力のポスト変数が空文字だったときには，全件検索になります．

しかし，これを実行して

```

    $sth->bindParam('requestID', $_POST['requestID'], PDO::PARAM_STR);
    
```

を行うとエラーになってしまい，`エラー: SQLSTATE[HY093]: Invalid parameter number`
というエラーメッセージが出ます．

しかしながら `:requestID` という書き方をやめて `?` で書き直し，全体を

```

        $sql = <<<SQL
        SELECT 
            * 
        FROM 
            Customers
        WHERE 
            requestID = 
            CASE
                WHEN ? = '' THEN
                    requestID
                ELSE
                    ?
            END
        SQL;
        $sth = $dbh->prepare($sql);
        $sth->bindParam(1, $_POST['requestID'], PDO::PARAM_STR);
        $sth->bindParam(2, $_POST['requestID'], PDO::PARAM_STR);
        $sth->execute();
    
```

と書き直すと今度は正常に動きます．

これはいったいどういうことでしょうか？なぜ `:name` 式の書き方だとエラーになってしまうのでしょうか？
CC BY-SA 4.0
2022-07-25T07:23:59.577
90186
2022-07-25T07:23:59.577
53010
question
php mysql
PHPのヒアドキュメント内のSQLのプレースホルダの挙動が，? と :name で何故か異なる