30454


下記を実行するたびに`jpy`は1足されていきます。

[code]

    $stmt = $pdo->prepare('UPDATE TABLE SET jpy = jpy + 1 WHERE ID = 1000');
    $stmt->execute();
    
[/code]

変更したい値を変数で変えたいのですが反映されません。

[code]

    $money = 'usd';
    $stmt = $pdo->prepare('UPDATE TABLE SET :money = :money + 1 WHERE ID = 1000');
    $stmt->bindParam(':money', $money, PDO::PARAM_STR);
    $stmt->execute();
    
[/code]

構文のように一つの行の一つのカラムの値をプラス1したいだけです。  
`?`を使ったり`PARAM_INT`や`bindValue`など試しましたがダメでした。  
`if`など使わずスマートにセキュアにダイナミックかつアグレッシブでフレキシブルに上記を反映させるにはどうすればよいですか？


CC BY-SA 3.0
2016-11-16T13:58:18.080
30451
2016-11-16T15:28:45.937
7973
question
pdo
MySQL PDOのprepareでUPDATE


PDOにおいて、また多くのDBのAPIにおいて、パラメータは値として扱われるので、列名をパラメータとして指定することはできません。

条件分岐をしたくないだけなら次のような書き方はできます。

[code]

    $money = 'usd';
    $sql_by_money = [
        'usd' => 'UPDATE TABLE SET usd = usd + 1 WHERE ID = 1000',
        'jpy' => 'UPDATE TABLE SET jpy = jpy + 1 WHERE ID = 1000',
        ...
    ];
    if (isset($sql_by_money[$money])) {
        $pdo->query($sql_by_money[$money]);
    }
    
[/code]

SQLを各パターン用意するのが嫌、あるいは現実的でないなら、文字列結合するしかないです。

[code]

    $money = 'usd';
    $pdo->query("UPDATE TABLE SET $money = $money + 1 WHERE ID = 1000");
    
[/code]

もちろん脆弱性を作りこみやすい方法ですから、この方法を選ぶのであれば埋め込む文字列をしっかり検証すべきです。例えば候補となる列名のリストを持っておき、それと一致するか確かめるなどするとよいでしょう。仮にパラメータとして列名が渡せたとしても、SQLインジェクションを防ぐことができるというだけで、意図せぬ列名が指定されることを防ぐことはできません。


CC BY-SA 3.0
2016-11-16T14:25:18.920
30454
2016-11-16T15:28:45.937
2016-11-16T15:28:45.937
8000
8000
30451
answer