db_affected_rows no Drupal 7 para db_query

8

Acabei de perceber que o @Berdir foi tão bom de remover db_affected_rowsdo Drupal 7 . Agora estou me perguntando qual é a melhor prática agora para detectar se a consulta que você executou mudou alguma coisa no banco de dados.

Um caso típico de uso seria.

db_query(...);
if (!db_affected_rows()) {
  db_query(...);
}

Dei uma olhada no objeto de consulta retornado de db_query, mas não pareceu muita ajuda.

Atualização:
Vejo que fiquei um pouco incerto sobre quais circunstâncias eu precisava das informações.

Meu caso de uso atual é bastante simples. Eu tenho uma tabela para um tipo de nó com uma coluna nid e algumas colunas de dados. Eu tenho um formulário e, ao enviar o formulário, desejo inserir ou atualizar a linha no banco de dados.

O problema com db_update/ db_inserté que, se eu usar a atualização primeiro e inserir se a atualização retornar 0, não capturarei a condição em que o formulário foi enviado com o valor no banco de dados. Se eu usar o db_insert primeiro, isso gerará um erro se já houver uma linha no db.

Suponho que nessa condição específica possa inserir um valor em branco quando o nó for criado e, em seguida, usar apenas a atualização, mas em alguns casos isso pode não ser possível, se eu precisar armazenar informações que foram codificadas em um banco de dados externo. Eu também gostaria de evitar ter que depender dos valores do banco de dados para que meu código funcione.

Minha estratégia usual para tais casos, foi fazer uma

db_query("INSERT IGNORE INTO ...")
if (!db_affected_rows()) {
  db_query("UPDATE ...");
}

Fazer isso é simples e sem erros, independentemente da condição em que o banco de dados estiver. A melhor opção que posso ver agora é lidar com o SQL e fazer o seguinte:

db_query("INSERT ... ON DUPLICATE KEY UPDATE");

Mas eu esperava que a API db fosse capaz de lidar com isso.

googletorp
fonte

Respostas:

9

Essas informações são retornadas diretamente pelo método execute () de Delete / UpdateQuery, consulte, por exemplo: UpdateQuery :: execute () .

<?php
$affected = db_update('some_table')
  ->fields(array(
    'some_field' => $value,
  ))
  ->condition('another_field', $id)
  ->execute();
?>

E InsertQuery :: execute () retorna o último ID de inserção.

Berdir
fonte
8

Depois de pesquisar, descobri que o Drupal fornece uma ferramenta nomeada pronta para o meu caso de uso exato:

Insira uma linha no banco de dados ou atualize a existente, se ela já estiver lá.

Isso é chamado de consultas de mesclagem , que podem ser feitas atomicamente para alguns mecanismos de banco de dados.

O texto é muito simples:

db_merge('example')
  ->key(array('name' => $name))
  ->fields(array(
    'field1' => $value1,
    'field2' => $value2,
))
->execute();
googletorp
fonte
Ah, sim, essa é a resposta correta para sua pergunta atualizada :) Observe que as consultas de mesclagem foram redesenhadas no final do ciclo de desenvolvimento do D7 para funcionarem como consultas SQL MERGE, que fazem parte do padrão SQL 2003, mas nenhum dbms realmente a implementa ainda , portanto, todos os dbms exigem duas consultas (elas são atômicas usando transações). O problema com a abordagem de consulta única que foi usada para o MySQL foi que ele ignorou completamente a definição key () e simplesmente trabalhou com as chaves únicas / primárias de uma determinada tabela.
Berdir 25/03
@ Berdir: Obrigado por me apontar na direção certa. Eu sou um daqueles desenvolvedores que gostam de escrever SQL e têm dificuldade em se acostumar com a nova API de banco de dados :) #
googletorp
Obrigado por este ponteiro. No entanto, tive que recorrer ao db_query de qualquer maneira, já que a API do Drupal db não permite o uso de constantes como CURRENT_TIMESTAMP (consulte drupal.org/node/215821 )
Whisky