我有一个类似
的数组Array (
[1] => 85590762,22412382,97998072
[3] => 22412382
)
其中key是item_id,value是我需要针对项目更新的列的值。我可以在循环中使用db_update但我想避免这种策略由于性能。我想更新单个db调用中的所有行。同样使用db_query我认为不是一个好主意。那么有没有办法使用db_update来更新这些行?
根据以上数据,标准的mysql查询将类似于
update items set sold= 1, users = '85590762,22412382,97998072' Where item_id = 1;
update items set sold = 1, users = '22412382' Where item_id = 3;
答案 0 :(得分:4)
很遗憾,你无法做到这一点。目前和可能在该功能中,不支持使用一个db_update更新具有不同值的不同行上的(多个)值。
如果您的数据是:
$for_update = array(
1 => "85590762,22412382,97998072",
3 => "22412382",
);
你可以这样做:
foreach ($for_update as $key => $value) {
$fields = array('sold' => 1, 'users' => $value);
db_update('items')->fields($fields)->condition('item_id', $key, '=')->execute();
}
优点:其他模块可以挂钩查询,可以支持多个DB驱动程序 缺点:对象初始化很慢,有很多数据库连接/流量
...因为在那种情况下没有对象实例化/操作,这是一个有点代价和其他转换。 (即:https://drupal.stackexchange.com/questions/129669/whats-faster-db-query-db-select-or-entityfieldquery)
foreach ($for_update as $key => $value) {
db_query("UPDATE items SET sold = :sold, users = :users WHERE item_id = :item_id",
array(':sold' => 1, ':users' => $value, ':item_id' => $key)
);
}
优点:没有对象初始化和操作<所以它更快了 缺点:其他模块无法挂钩查询,您的代码可能会在不同的数据库驱动程序,大量数据库连接/流量下中断
在某些情况下,这可以提高你的表现。
$transaction = db_transaction();
try {
foreach ($for_update as $key => $value) {
$fields = array('sold' => 1, 'users' => $value);
db_update('items')->fields($fields)->condition('item_id', $key, '=')->execute();
}
}
catch (Exception $e) {
$transaction->rollback();
watchdog_exception('my_type', $e);
}
注意:当你想要一切或什么也没有时,交易最常用。但是对于某些DB驱动程序,您可以优化COMMIT命令 在案例1中你会得到这样的东西:
UPDATE items SET sold = 1, users = '85590762,22412382,97998072' WHERE item_id = 1;
COMMIT;
UPDATE items SET sold = 1, users = '22412382' WHERE item_id = 3;
COMMIT;
通过交易,您可以执行以下操作:
UPDATE items SET sold = 1, users = '85590762,22412382,97998072' WHERE item_id = 1;
UPDATE items SET sold = 1, users = '22412382' WHERE item_id = 3;
COMMIT;
使用COMMIT,您可以将数据写入最终位置(进入长期存储,直到此,它只在内存中的某个位置或临时位置)。使用回滚时,将删除这些更改。至少这是我理解这一点的方式。 (即当我使用sqlite时,我的性能得到了提升。)
与案例1或2 +
相同
优点:如果需要保持一致,可以回滚数据,只将数据写入驱动器一次<所以只有sql"一次"做IO,很多数据库连接/流量
$ids = array();
$when_then = "";
foreach ($for_update as $key => $value) {
$ids[] = $key;
$when_then .= "WHEN $key THEN '$value' ";
}
db_query("UPDATE items
SET sold = 1, users = CASE item_id
$when_then
ELSE users
END
WHERE item_id IN(:item_ids)", array(':item_ids' => $ids));
这可能是所有人从这里开始的最快方式
注意:$when_then
变量不包含最佳解决方案,如果您可以使用params或者您逃脱不安全的数据,那么它会更好。
优点:在你的服务器和sql之间只有一个请求和更少的冗余数据,一个更大的sql查询比很多小的查询更快 缺点:其他模块无法挂钩查询,您的代码可能会在不同的DB驱动程序下破解
另请注意,在(我认为)PHP 5.3之后,您无法在db_query或PDO中默认运行多个语句,因为它可以是SQL注入,因此它会阻塞。但是你可以设置它,但不推荐。 (PDO support for multiple queries (PDO_MYSQL, PDO_MYSQLND))
13-05-2019编辑:
我只是在几个月前对中型数据集进行了一些性能测量,以便通过db_select
和db_query
查询一些数据。这些性能的大小是:在运行一个db_select
下,您可以运行两个db_query
。这也适用于db_update
和db_query
。测试用一个简单的SELECT
查询了一些列,没有JOINS
,没有花哨的花花公子的东西,只有两个条件。当然,测量还包含/包括构建这些查询所需的时间(在两种情况下)。但请注意,Drupal Coding Standard要求正常使用db_update
,db_delete
,db_merge
,只允许'允许' db_query
代替db_select
操作。
答案 1 :(得分:0)
注意:通过批量更新,只能将一个查询发送到服务器,而不是针对要更新的每一行发送一个查询。
语法:
UPDATE yourTableName
SET yourUpdateColumnName =
(CASE yourConditionColumnName WHEN Value1 THEN 'UpdatedValue'
WHEN Value2 THEN 'UpdatedValue'
.
.
N
END)
WHERE yourConditionColumnName IN(Value1,Value2,.....N);
有关UpdateQuery上表达式的更多信息,位于: https://api.drupal.org/api/drupal/includes%21database%21query.inc/function/UpdateQuery%3A%3Aexpression/7.x
您的数据将是:
//Create array
$for_update = [
1 => "85590762,22412382,97998072",
3 => "22412382",
];
$item_ids_to_filter = [];
//Setup when-then conditions
$when_then = "CASE item_id ";
foreach ($for_update as $item_id => $users_id) {
$when_then .= "WHEN {$item_id} THEN '{$users_id}' ";
$item_ids_to_filter[] = $item_id;
}
$when_then .= "END";
//Execute query and update the data with db_update
db_update('items')
->expression("users",$when_then)
->condition('item_id', $item_ids_to_filter)
->execute();
结果将生成下一个查询:
UPDATE items
SET users =
(CASE item_id = WHEN 1 THEN '85590762,22412382,97998072'
WHEN 3 THEN '22412382'
END)
WHERE (item_id IN ('1', '3'))
答案 2 :(得分:-2)
我认为你可以做点什么
$query = db_udpate('table')->fields(array('field_1','field_2','field_3'));
foreach ($fields as $record) {
$query->values($record);
}
return $query->execute();
$ fields = array('field_1'=> VALUE,'field_2'=> VALUE)