原则 - 如何将数组绑定到 SQL?

2022-08-30 16:06:27

我的 SQL 看起来像这样:

$sql = "select * from user where id in (:userId) and status = :status";

$em = $this->getEntityManager();
$stmt = $em->getConnection()->prepare($sql);
$stmt->bindValue(':userId', $accounts, \Doctrine\DBAL\Connection::PARAM_INT_ARRAY);
$stmt->bindValue(':status', 'declined');
$stmt->execute();

$result = $stmt->fetchAll();

但它返回:

执行时发生异常 (...)

与参数 [[1,2,3,4,5,6,7,8,11,12,13,14],“已拒绝”]

注意:数组到字符串的转换

我无法使用,因为我的实际SQL更复杂(例如,包含联接选择,联合等)queryBuilder


答案 1

不能仅仅因为 sql 本身不支持数组而将预准备语句与数组一起使用。这真是太可惜了。在这条线的某个地方,您实际上需要确定您的数据是否包含三个项目并发出IN(?,?,?)。Doctrine ORM实体管理器会自动为您执行此操作。

幸运的是,DBAL可以满足您的需求。你只是不使用绑定或准备。该手册有一个例子:https://www.doctrine-project.org/projects/doctrine-dbal/en/latest/reference/data-retrieval-and-manipulation.html#list-of-parameters-conversion

在你的情况下,它看起来像这样:

$sql = "select * from user where id in (?) and status = ?";
$values = [$accounts,'declined'];
$types = [Connection::PARAM_INT_ARRAY, \PDO::PARAM_STR];
$stmt = $conn->executeQuery($sql,$values,$types);
$result = $stmt->fetchAll();

上面的代码未经测试,但你应该明白了。(确保你为use Doctrine\DBAL\Connection;Connection::PARAM_INT_ARRAY)

使用命名参数的人员请注意:

如果使用命名参数(而不是 ),则在提供类型时应遵循参数名称。例如::param?

$sql = "select * from user where id in (:accounts) and status = :status";
$values = ['accounts' => $accounts, 'status' => 'declined'];
$types = ['accounts' => Connection::PARAM_INT_ARRAY, 'status' => \PDO::PARAM_STR];

答案 2

如果你想坚持顺序无关紧要的语法,你必须做一些额外的工作,但我会告诉你一种更简单的方法来绑定参数::param

// store all your parameters in one array
$params = array(
    ':status' => 'declined'
);

// then, using your arbitrary array of id's ...
$array_of_ids = array(5, 6, 12, 14);

// ... we're going to build an array of corresponding parameter names
$id_params = array();
foreach ($array_of_ids as $i => $id) {
    // generate a unique name for this parameter
    $name = ":id_$i"; // ":id_0", ":id_1", etc.

    // set the value
    $params[$name] = $id;

    // and keep track of the name
    $id_params[] = $name;
}

// next prepare the parameter names for placement in the query string
$id_params = implode(',', $id_params); // ":id_0,:id_1,..."
$sql = "select * from user where id in ($id_params) and status = :status";

在这种情况下,我们最终得到:"select * from user where id in (:id_0,:id_1,:id_2,:id_3) and status = :status"

// now prepare your statement like before...
$stmt = $em->getConnection()->prepare($sql);

// ...bind all the params in one go...
$stmt->execute($params);

// ...and get your results!
$result = $stmt->fetchAll();

此方法还将适用于字符串数组。


推荐