Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/php/248.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Php 当字符串被绑定时,将WHERE IN(…)与PDO一起使用不起作用_Php_Mysql_Pdo - Fatal编程技术网

Php 当字符串被绑定时,将WHERE IN(…)与PDO一起使用不起作用

Php 当字符串被绑定时,将WHERE IN(…)与PDO一起使用不起作用,php,mysql,pdo,Php,Mysql,Pdo,我有一个如下的查询: UPDATE table SET column = UNIX_TIMESTAMP() WHERE id IN (:idString) UPDATE table SET column = UNIX_TIMESTAMP() WHERE id IN (' . $idString . ') 其中,idString是由逗号分隔的ID组成的字符串,它被传递到数组中执行。令我惊讶的是,当执行此查询时,只有idString中第一个id的行被更新 在我的头撞在墙上一段时间

我有一个如下的查询:

  UPDATE table SET column = UNIX_TIMESTAMP()
  WHERE id IN (:idString)
  UPDATE table SET column = UNIX_TIMESTAMP()
  WHERE id IN (' . $idString . ')
其中,idString是由逗号分隔的ID组成的字符串,它被传递到数组中执行。令我惊讶的是,当执行此查询时,只有idString中第一个id的行被更新

在我的头撞在墙上一段时间后,我最终决定这样尝试:

  UPDATE table SET column = UNIX_TIMESTAMP()
  WHERE id IN (:idString)
  UPDATE table SET column = UNIX_TIMESTAMP()
  WHERE id IN (' . $idString . ')
第二个查询按预期工作

当我使用PDO绑定ID字符串时,为什么查询不起作用?

在SQL中,字符串

'1,2,3,5,12'
是单个值,在数字上下文中转换它,它将只具有前导数字的值,因此只有值1

这与多个值的集合大不相同:

'1', '2', '3', '5', '12'
无论何时使用绑定参数,作为参数值传递的任何内容都只会变成一个值,即使传递的是逗号分隔的值字符串也是如此

如果要将一组多个值传递给SQL查询中的参数,则必须具有多个参数占位符:

UPDATE table SET column = UNIX_TIMESTAMP()
WHERE id IN (:id1, :id2, :id3, :id4, :id5)
然后分解值字符串并将其作为数组传递:

$idlist = array('id1' => 1, 'id2' => 2, 'id3' => 3, 'id4' => 5, 'id5' => 12);
$pdoStmt->execute($idlist);
对于这种情况,我建议使用位置参数而不是命名参数,因为可以传递简单数组而不是关联数组:

$pdoStmt = $pdo->prepare("UPDATE table SET column = UNIX_TIMESTAMP()
    WHERE id IN (?, ?, ?, ?, ?)");
$idlist = explode(",", "1,2,3,5,12");
$pdoStmt->execute($idlist);
@mario添加了一条您可以使用的注释。该查询将允许您传递一个以逗号分隔的值字符串格式的字符串:

$pdoStmt = $pdo->prepare("UPDATE table SET column = UNIX_TIMESTAMP()
    WHERE FIND_IN_SET(id, :idString)");
$pdoStmt->execute(["idString" => "1,2,3,5,12"]);
但是,我通常不推荐使用该函数,因为它破坏了使用索引缩小搜索范围的任何机会。它实际上必须检查表中的每一行,并且在更新期间,这意味着它必须锁定表中的每一行。

在SQL中,字符串

'1,2,3,5,12'
是单个值,在数字上下文中转换它,它将只具有前导数字的值,因此只有值1

这与多个值的集合大不相同:

'1', '2', '3', '5', '12'
无论何时使用绑定参数,作为参数值传递的任何内容都只会变成一个值,即使传递的是逗号分隔的值字符串也是如此

如果要将一组多个值传递给SQL查询中的参数,则必须具有多个参数占位符:

UPDATE table SET column = UNIX_TIMESTAMP()
WHERE id IN (:id1, :id2, :id3, :id4, :id5)
然后分解值字符串并将其作为数组传递:

$idlist = array('id1' => 1, 'id2' => 2, 'id3' => 3, 'id4' => 5, 'id5' => 12);
$pdoStmt->execute($idlist);
对于这种情况,我建议使用位置参数而不是命名参数,因为可以传递简单数组而不是关联数组:

$pdoStmt = $pdo->prepare("UPDATE table SET column = UNIX_TIMESTAMP()
    WHERE id IN (?, ?, ?, ?, ?)");
$idlist = explode(",", "1,2,3,5,12");
$pdoStmt->execute($idlist);
@mario添加了一条您可以使用的注释。该查询将允许您传递一个以逗号分隔的值字符串格式的字符串:

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

但是,我通常不推荐使用该函数,因为它破坏了使用索引缩小搜索范围的任何机会。它实际上必须检查表中的每一行,并且在更新期间,这意味着它必须锁定表中的每一行。

您试图将字符串作为集合传递给准备好的语句。MySQL正在尝试执行查询

-- assuming idString is "1,2,3,4,5"
UPDATE table SET column = UNIX_TIMESTAMP() WHERE id IN ("1,2,3,4,5");
而不是

UPDATE table SET column = UNIX_TIMESTAMP() WHERE id IN (1,2,3,4,5);
你要么用这个语句

UPDATE table SET column = UNIX_TIMESTAMP() WHERE id == ?

并对所有id执行它,或者通过将id字符串注入查询来准备语句

您试图将字符串作为集合传递给准备好的语句。MySQL正在尝试执行查询

-- assuming idString is "1,2,3,4,5"
UPDATE table SET column = UNIX_TIMESTAMP() WHERE id IN ("1,2,3,4,5");
而不是

UPDATE table SET column = UNIX_TIMESTAMP() WHERE id IN (1,2,3,4,5);
你要么用这个语句

UPDATE table SET column = UNIX_TIMESTAMP() WHERE id == ?

并对您拥有的多个id执行它,或者通过向查询中注入id字符串来准备语句

您的工作解决方案不好,因为它受到SQL注入的影响。
-- assuming idString is "1,2,3,4,5"
UPDATE table SET column = UNIX_TIMESTAMP() WHERE id IN ("1,2,3,4,5");
它不起作用的原因是您正在分配数组,而不是普通的逗号分隔值。 必须使用内爆来分隔数组的值,然后将逗号分隔的值分配给pdo可以使用的变量

否则,您可以使用而不是:$idString、?在select语句中,并从和数组中执行准备好的语句,该数组保存$idString

$query=$db->prepare("Select a From table where b =? order by 1;"); $query->execute(array($idString));
您的工作解决方案不好,因为它受到SQL注入的影响。 它不起作用的原因是您正在分配数组,而不是普通的逗号分隔值。 必须使用内爆来分隔数组的值,然后将逗号分隔的值分配给pdo可以使用的变量

否则,您可以使用而不是:$idString、?在select语句中,并从和数组中执行准备好的语句,该数组保存$idString

$query=$db->prepare("Select a From table where b =? order by 1;"); $query->execute(array($idString));
绑定时,PDO需要一个值。考虑到上面的$idString,如果您有源数组,这样做会更好

$ids = explode(',', $idString);
$placeholders = implode(', id', array_keys($ids));
if($placeholders) {
    $placeholders = 'id' . $placeholders;
    $sql = "UPDATE table SET column = UNIX_TIMESTAMP()
         WHERE id IN ({$placeholders})";

    // prepare your statement, yielding "$st", a \PDOStatement
    $st = $pdo->prepare($sql);

    // bind every placeholder
    foreach($ids as $key => $id) {
        $st->bindValue("id{$key}", $id);
    }

    // execute
    $st->execute();
}

绑定时,PDO需要一个值。考虑到上面的$idString,如果您有源数组,这样做会更好

$ids = explode(',', $idString);
$placeholders = implode(', id', array_keys($ids));
if($placeholders) {
    $placeholders = 'id' . $placeholders;
    $sql = "UPDATE table SET column = UNIX_TIMESTAMP()
         WHERE id IN ({$placeholders})";

    // prepare your statement, yielding "$st", a \PDOStatement
    $st = $pdo->prepare($sql);

    // bind every placeholder
    foreach($ids as $key => $id) {
        $st->bindValue("id{$key}", $id);
    }

    // execute
    $st->execute();
}

或者使用FIND_IN_SET或者使用FIND_IN_SET+1关于SQL注入的优点。在我的例子中,我使用的是从上一个查询中检索到的整数行ID,所以这是安全的,但一般来说,使用未绑定变量是绝对正确的
美国..+1关于SQL注入的优点。在我的例子中,我使用的是从上一个查询中检索到的整数行ID,所以它是安全的,但一般来说,您绝对正确地认为使用未绑定变量是危险的。。