douzhe2981 2014-01-16 22:21
浏览 128
已采纳

在绑定字符串时,使用带有PDO的WHERE IN(...)不起作用

I have a query that looks like this:

  UPDATE table SET column = UNIX_TIMESTAMP()
  WHERE id IN (:idString)

Where idString is a string of comma separated ids and is passed to execute() in an array. To my surprise, when this query is executed, only the row with the first id in idString is updated.

After banging my head against the wall for a while, I finally decided to try it like this:

  UPDATE table SET column = UNIX_TIMESTAMP()
  WHERE id IN (' . $idString . ')

The second query works as expected.

Why won't the query work when I bind the string of ids using PDO?

  • 写回答

4条回答 默认 最新

  • dongxie45083 2014-01-16 22:25
    关注

    In SQL, the string

    '1,2,3,5,12'
    

    Is a single value, and casting it in a numeric context, it will just have the value of the leading digits, so just the value 1.

    This is much different from the set of multiple values:

    '1', '2', '3', '5', '12'
    

    Any time you use bound parameters, whatever you pass as the parameter value becomes just one single value, even if you pass a string of comma-separated values.

    If you want to pass a set of multiple values to parameters in your SQL query, you must have multiple parameter placeholders:

    UPDATE table SET column = UNIX_TIMESTAMP()
    WHERE id IN (:id1, :id2, :id3, :id4, :id5)
    

    Then explode your string of values and pass them as an array:

    $idlist = array('id1' => 1, 'id2' => 2, 'id3' => 3, 'id4' => 5, 'id5' => 12);
    $pdoStmt->execute($idlist);
    

    For cases like this, I would recommend using positional parameters instead of named parameters, because you can pass a simple array instead of an associative array:

    $pdoStmt = $pdo->prepare("UPDATE table SET column = UNIX_TIMESTAMP()
        WHERE id IN (?, ?, ?, ?, ?)");
    $idlist = explode(",", "1,2,3,5,12");
    $pdoStmt->execute($idlist);
    

    @mario adds a comment that you can use FIND_IN_SET(). That query would look allow you to pass one string formatted as a comma-separated string of values:

    $pdoStmt = $pdo->prepare("UPDATE table SET column = UNIX_TIMESTAMP()
        WHERE FIND_IN_SET(id, :idString)");
    $pdoStmt->execute(["idString" => "1,2,3,5,12"]);
    

    However, I usually don't recommend that function because it spoils any chance of using an index to narrow down the search. It will literally have to examine every row in the table, and during an UPDATE that means it has to lock every row in the table.

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论
查看更多回答(3条)

报告相同问题?

悬赏问题

  • ¥15 目前主流的音乐软件,像网易云音乐,QQ音乐他们的前端和后台部分是用的什么技术实现的?求解!
  • ¥60 pb数据库修改与连接
  • ¥15 spss统计中二分类变量和有序变量的相关性分析可以用kendall相关分析吗?
  • ¥15 拟通过pc下指令到安卓系统,如果追求响应速度,尽可能无延迟,是不是用安卓模拟器会优于实体的安卓手机?如果是,可以快多少毫秒?
  • ¥20 神经网络Sequential name=sequential, built=False
  • ¥16 Qphython 用xlrd读取excel报错
  • ¥15 单片机学习顺序问题!!
  • ¥15 ikuai客户端多拨vpn,重启总是有个别重拨不上
  • ¥20 关于#anlogic#sdram#的问题,如何解决?(关键词-performance)
  • ¥15 相敏解调 matlab