db_affected_rows en Drupal 7 para db_query


8

Acabo de notar que @Berdir fue muy agradable de eliminar db_affected_rowsde Drupal 7 . Ahora me pregunto cuál es la mejor práctica para detectar si la consulta que ejecutó cambió algo en la base de datos.

Un caso de uso típico sería

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

Eché un vistazo al objeto de consulta devuelto por db_query, pero no me pareció de mucha ayuda.

Actualización:
veo que no estaba claro en qué circunstancias necesitaba la información.

Mi caso de uso actual es bastante simple. Tengo una tabla para un tipo de nodo con una columna nid y algunas columnas de datos. Tengo un formulario y al enviar el formulario, quiero insertar o actualizar la fila en la base de datos.

El problema con db_update/ db_insertes que, si uso la actualización primero, y la inserto si la actualización devuelve 0, no captaré la condición, donde el formulario se envió con el valor en la base de datos. Si uso db_insert primero, eso generará un error si ya hay una fila en la base de datos.

Supongo que en esta condición específica podría insertar un valor en blanco cuando se crea el nodo y luego solo usar la actualización, pero en algunos casos eso podría no ser posible, si necesito almacenar información que fue ingresada en una base de datos externa. También me gustaría evitar tener que depender de los valores de la base de datos para que mi código funcione.

Mi estrategia habitual para tales casos ha sido hacer un

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

Hacer esto es simple y sin errores, sin importar en qué condición se encuentre la base de datos. La mejor opción que puedo ver en este momento sería manejarlo con SQL y hacer esto:

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

Pero esperaba que la API de db pudiera manejar esto.

Respuestas:


9

Esa información es devuelta directamente por el método execute () de Delete / UpdateQuery, vea por ejemplo: UpdateQuery :: execute () .

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

Y InsertQuery :: execute () devuelve la última identificación de inserción.


8

Después de investigar, descubrí que Drupal proporciona una herramienta lista para mi caso de uso exacto:

Inserte una fila en la base de datos o actualice la existente si ya está allí.

Esto se llama consultas de fusión , que se pueden hacer atómicamente para algunos motores db.

El syntext es bastante simple:

db_merge('example')
  ->key(array('name' => $name))
  ->fields(array(
    'field1' => $value1,
    'field2' => $value2,
))
->execute();

Ah sí, esa es la respuesta correcta para su pregunta actualizada :) Tenga en cuenta que las consultas de fusión se han rediseñado al final del ciclo de desarrollo de D7 para que realmente funcionen como consultas SQL de MERGE, que son parte del estándar SQL 2003, pero todavía no lo implementa dbms , por lo que todos los dbms requieren dos consultas (se hacen atómicas mediante el uso de transacciones). El problema con el enfoque de consulta única que se usó para MySQL fue que ignoró por completo la definición de la clave () y simplemente trabajó con las claves únicas / primarias de una tabla dada.
Berdir

@ Berdir: Gracias por señalarme en la dirección correcta. Soy uno de esos desarrolladores a los que les gusta escribir SQL y les cuesta acostumbrarse a la nueva API de db :)
googletorp

Gracias por este puntero. Sin embargo, tuve que recurrir a db_query de todos modos ya que la drupal db api no permite el uso de constantes como CURRENT_TIMESTAMP (ver drupal.org/node/215821 )
Whisky
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.