Drupal 7 / actualizar várias linhas com a actualização do db
tenho uma matriz como
Array (
[1] => 85590762,22412382,97998072
[3] => 22412382
)
onde a chave é o item_id e o valor é o valor de uma coluna que preciso actualizar em relação a um item. Eu posso usar DB_ Update em um loop mas eu quero evitar esta estratégia devido ao desempenho. Eu quero atualizar todas as linhas em uma única chamada db. Também usando db_query eu acho que não será uma boa idéia. Existe alguma forma de usar o DB_ Update para actualizar estas linhas?
de acordo com os dados acima, as consultas padrão do mysql serão como
update items set sold= 1, users = '85590762,22412382,97998072' Where item_id = 1;
update items set sold = 1, users = '22412382' Where item_id = 3;
2 answers
Se os seus dados são estes:
$for_update = array(
1 => "85590762,22412382,97998072",
3 => "22412382",
);
Podes fazer isto:
Caso 1: Criar um ciclo e ligar sempre que a função de actualização:
foreach ($for_update as $key => $value) {
$fields = array('sold' => 1, 'users' => $value);
db_update('items')->fields($fields)->condition('item_id', $key, '=')->execute();
}
Prós: outros módulos podem encaixar-se dentro da sua pesquisa, podem suportar múltiplos drivers de DB
Cons: a inicialização do objecto é lenta, muito DB ligação / tráfego
Caso 2: é mais rápido se você usar db_query()...
... porque nesse caso não há instanciação/Operação de objeto, o que é um pouco caro e outra conversão. (isto é: 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)
);
}
Prós: sem inicialização de objetos e operação por isso é mais rápido Cons: outros módulos não podem se conectar dentro de sua consulta, seu código pode quebrar sob DB diferente condutores, muita ligação DB/tráfego
Caso 3: também pode usar a transacção
Isto pode aumentar um pouco o teu desempenho em algum caso.$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);
}
Nota: transacção utilizada principalmente, quando se quer tudo ou nada. Mas com alguns drivers DB, você pode otimizar os comandos COMMIT.
No caso de se ter algo assim:
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;
Com a transacção fazes algo assim:
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;
Com o COMMIT você escreve os dados para o local final (em armazenamento de longo prazo, até isso, é apenas em algum lugar na memória ou um lugar temporário). Quando você usa rollback, você deixa cair essas alterações. Pelo menos é assim que eu entendo isto. (ou seja, eu recebo melhoria de desempenho com isso quando eu usei sqlite.)
O mesmo que o caso 1 ou 2 +
Prós: você pode rever os seus dados se você precisa ser consistente, você escreve os dados apenas uma vez para a unidade
Caso 4: ou pode construir um sql declaração para isto:
$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));
Provavelmente este é o caminho mais rápido a partir daqui.Nota:
$when_then
a variável não contém a melhor solução, é melhor se puder usar os parâmetros ou escapar a dados inseguros.
Prós: entre o seu servidor e o sql haverá apenas um pedido e dados menos redundantes, uma maior pesquisa de sql mais rápido do que muitos pequenos
Cons: outros módulos não podem entrar na sua consulta, o seu código pode quebrar sob diferentes drivers de DB
Também por favor, note, após (eu acho) PHP 5.3 você não pode executar mais de uma declaração em db_query ou na DOP por padrão, por causa de que pode ser uma injeção SQL, por isso bloqueia. No entanto, você pode definir isso, mas não recomendado. ( suporte DOP para múltiplas consultas (PDO_MYSQL, PDO_MYSQLND))
$query = db_udpate('table')->fields(array('field_1','field_2','field_3'));
foreach ($fields as $record) {
$query->values($record);
}
return $query->execute();
Em que $fields = array ('field_1' = > valor,' field_2 ' = > valor)