在Yii2中使用MySQL“IN”语法绑定参数的正确方法?

twh00eeo  于 2022-11-09  发布在  Mysql
关注(0)|答案(7)|浏览(241)

好的,我使用的是Yii2,并且我熟悉在使用mysql查询时准备/绑定数据,例如:

$sql = $this->db->createCommand("UPDATE some_table SET something='foo' WHERE some_id=:some_id");
$sql->bindValue(':some_id', $some_id);

但是,如果值 * 可以 * 包含多个值,比如使用MySQL语法IN时,该怎么办呢?
例如:

$sql = $this->db->createCommand("UPDATE some_table SET something='foo' WHERE some_id IN (:parents)");
$sql->bindValue(':parents', $parents);

现在,我明白了,只有当$parents变量只有 * 一个 * 值时,上面的方法才能很好地工作;但是如果它有多个值,比如1,2,3,那么当你真正需要'1','2','3'1,2,3时,你最终会得到'1,2,3'这样的结果。
正确的做法是什么?

7rtdyuoh

7rtdyuoh1#

我找到了解决办法

$params = [];
$sql = \Yii::$app->db->getQueryBuilder()->buildCondition(['IN', 'some_id', $ids], $params);
//$sql = some_id NOT IN (:qp0, :qp1, :qp2)
//$params = [':qp0'=>1, ':qp1'=>2, ':qp2'=>3]
$this->db->createCommand("UPDATE some_table SET something='foo' WHERE $sql", $params);
t9eec4r0

t9eec4r02#

您可以使用Yii的QueryBuilder函数,一切都会自动处理。试试这个:

$params = [];
$sql = \Yii::$app->db->getQueryBuilder()->update('some_table', ['something' => 'foo'], ['some_id' => [1, 2, 3]], $params);

结果是:

string(78) "UPDATE `some_table` SET `something`=:qp0 WHERE `some_id` IN (:qp1, :qp2, :qp3)"
array(4) { [":qp0"]=> string(3) "foo" [":qp1"]=> int(1) [":qp2"]=> int(2) [":qp3"]=> int(3) }
hgncfbus

hgncfbus3#

Yii 2的数据库函数是基于PDO的。根据bindValue的手册,不支持Array类型的值。(第三个参数-data_type)。
解决方案是在查询之前创建一个字符串,该字符串适合您的IN子句,并将其绑定为字符串。
类似于:

$parents = "1,2,3";
/*
Or in case you already have an array of the desirable ids:
$parents_array = array(1,2,3);
$parents = implode(",",$parents_array);

* /

$sql = $this->db->createCommand("UPDATE some_table SET something='foo' WHERE some_id IN (:parents)");
$sql->bindValue(':parents', $parents);

编辑

占位符似乎被内爆数组替换为一个字符串值'1,2,3',而不是'1','2','3'(因为它是一个占位符)。
为了解决这个问题,我建议使用多个?占位符,这样就不用IN (:parents)了,因为我们已经有了一个排列好的数组-我们可以使用count($array)来知道我们需要放置多少占位符。

//$parents = array(1,2,3);
$placeholders = str_repeat('?,', count($parents) - 1). '?';
$sql = $this->db->createCommand("UPDATE some_table SET something='foo' WHERE some_id IN (".$placeholders.")");

foreach($parents as $i => $parent){
 $sql->bindValue($i+1, $parent);  
}

请注意bindValue的第一个参数的传递值;手册中提到的是$i+1而不是$i的原因:
对于使用问号占位符的预准备语句,这将是参数的1索引位置
有关详细信息和替代解决方案,请参阅以下答案:https://stackoverflow.com/a/920523/998096

zc0qhyus

zc0qhyus4#

如果数据是可信的,则此解决方案非常有效:

$db = Yii::$app->db;
$ids = "'" . implode("','", $ids_array) . "'";
$result = $db->createCommand("
    UPDATE some_table SET something='foo' WHERE some_id IN ($ids)
")->queryColumn();
ubof19bj

ubof19bj5#

我最后是这样做的:

$parents_safe = '';
$parents_sep = explode(',', $parents);

foreach ($parents_sep as $parent) {
    $parents_safe .= $this->db->quoteValue($parent) . ',';
}

$parents_safe = rtrim($parents_safe, ',');

其中,$this->dbYii::$app->db的一个示例。

5lwkijsr

5lwkijsr6#

如果有人需要Yii1的解决方案:

$db = \Yii::app()->db;

$inCondition = $db
    ->getCommandBuilder()
    ->createInCondition('some_table', 'some_id', $parents);

$command = $db
    ->createCommand("UPDATE some_table SET something = :foo WHERE $inCondition");

$command->bindValue(':foo', 'foo');
$command->execute();
ttisahbt

ttisahbt7#

只管做

$parents = implode("','", $parrent_array);
$sql->bindValue(':parents', $parents);

应该可以了。

相关问题