db_affected_rows dans Drupal 7 pour db_query

8

Je viens de remarquer que @Berdir était si agréable à supprimer db_affected_rowsde Drupal 7 . Je me demande maintenant quelle est la meilleure pratique pour détecter si la requête que vous avez exécutée a changé quelque chose dans la base de données.

Un cas d'utilisation typique serait de.

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

J'ai jeté un œil à l'objet de requête renvoyé par db_query, mais cela ne semblait pas être d'une grande aide.

Mise à jour:
je vois que je ne savais pas trop dans quelles circonstances j'avais besoin des informations.

Mon cas d'utilisation actuel est assez simple. J'ai une table pour un type de nœud avec une colonne nid et quelques colonnes de données. J'ai un formulaire et en soumettant le formulaire, je veux insérer ou mettre à jour la ligne dans la base de données.

Le problème avec db_update/ db_insertest que, si j'utilise d'abord la mise à jour et que j'insère si la mise à jour renvoie 0, je n'attraperai pas la condition, où le formulaire a été soumis avec la valeur dans la base de données. Si j'utilise d'abord db_insert, cela soulèvera une erreur s'il y a déjà une ligne dans la base de données.

Je suppose que dans cette condition spécifique, je pourrais insérer une valeur vide lorsque le nœud est créé et utiliser uniquement la mise à jour, mais dans certains cas, cela pourrait ne pas être possible, si j'avais besoin de stocker des informations qui étaient saisies dans une base de données externe. Je voudrais également éviter d'avoir à dépendre des valeurs de la base de données pour que mon code fonctionne.

Ma stratégie habituelle pour de tels cas a été de faire un

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

Faire cela est à la fois simple et sans erreur quelle que soit la condition dans laquelle se trouve la base de données. La meilleure option que je peux voir en ce moment, serait de la gérer avec SQL et de faire ceci:

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

Mais j'espérais que l'API db serait capable de gérer cela.

googletorp
la source

Réponses:

9

Ces informations sont directement renvoyées par la méthode execute () de Delete / UpdateQuery, voir par exemple: UpdateQuery :: execute () .

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

Et InsertQuery :: execute () renvoie le dernier identifiant d'insertion.

Berdir
la source
8

Après avoir creusé, j'ai trouvé que Drupal fournit un outil nommé pour mon cas d'utilisation exact:

Insérez une ligne dans la base de données ou mettez à jour l'existant s'il existe déjà.

C'est ce qu'on appelle des requêtes de fusion , qui peuvent être effectuées de manière atomique pour certains moteurs de base de données.

Le syntext est assez simple:

db_merge('example')
  ->key(array('name' => $name))
  ->fields(array(
    'field1' => $value1,
    'field2' => $value2,
))
->execute();
googletorp
la source
Ah oui, c'est la bonne réponse à votre question mise à jour :) Notez que les requêtes de fusion ont été repensées à la fin du cycle de développement D7 pour fonctionner comme les requêtes MERGE sql, qui font partie de la norme SQL 2003, mais aucun dbms ne l'implémente encore , donc tous les dbms nécessitent deux requêtes (elles sont rendues atomiques à l'aide de transactions). Le problème avec l'approche de requête unique utilisée pour MySQL était qu'elle ignorait complètement la définition de key () et fonctionnait simplement avec les clés uniques / primaires d'une table donnée.
Berdir
@Berdir: Merci de m'avoir pointé dans la bonne direction. Je fais partie de ces développeurs qui aiment écrire du SQL et qui ont du mal à s’habituer à la nouvelle API db :)
googletorp
Merci pour ce pointeur. Cependant, j'ai dû recourir à db_query de toute façon car l'api db Drupal ne permet pas d'utiliser des constantes comme CURRENT_TIMESTAMP (voir drupal.org/node/215821 )
Whisky