Trabajar con bases de datos en Drupal 7 - Lección 11 - Consultas MERGE
Las consultas de fusión (merge) son un tipo especial de consultas híbridas. Aunque la sintaxis para este tipo de consultas fue definida en SQL 2003, en realidad casi ninguna base de datos la soporta directamente. Sin embargo, la mayoría de las bases de datos proporcionan una implementación alternativa usando sintaxis específica. El constructor de consultas de fusión en Drupal abstrae el concepto de consulta de fusión dentro de una estructura de objeto, de modo que dicho objeto puede compilarse de forma diferente para cada base de datos según sus particularidades.
En términos generales, una consulta de fusión es una combinación de una consulta de inserción y una de actualización. Si se cumple una condición, es decir, si ya existe una fila con una clave determinada, se ejecuta una consulta. Si no, se ejecuta otra. En la mayoría de los casos, esto equivale a lo siguiente:
<?php if (db_result(db_query("SELECT COUNT(*) FROM {example} WHERE id=:id", array(':id' => $id))->fetchField())) { // Ejecutar una actualización con WHERE id = $id } else { // Ejecutar una inserción insertando $id para id } ?>
La implementación real depende de la base de datos específica. Ten en cuenta que, aunque conceptualmente las consultas de fusión son operaciones atómicas, pueden o no ser verdaderamente atómicas según la implementación de cada motor de base de datos. Por ejemplo, en MySQL esta operación es atómica, pero no lo es en el ejemplo anterior.
Ejemplo básico
<?php db_merge('example') ->key(array('name' => $name)) ->fields(array( 'field1' => $value1, 'field2' => $value2, )) ->execute(); ?>
En este ejemplo, trabajamos con la tabla "example". Indicamos un campo clave name
con el valor $name
, y definimos un conjunto de campos con valores a establecer. Si ya existe una fila con name = $name
, entonces field1
y field2
serán actualizados. Si no, se insertará una nueva fila con name
, field1
y field2
.
Definir acciones según condición
A veces es necesario aplicar diferentes valores dependiendo de si la fila existe o no. Se puede hacer así:
<?php db_merge('example') ->key(array('name' => $name)) ->fields(array( 'field1' => $value1, 'field2' => $value2, )) ->updateFields(array( 'field1' => $alternate1, )) ->execute(); ?>
En este caso, si la fila ya existe, field1
se actualizará con $alternate1
. Si no existe, se insertará con los valores normales de field1
y field2
.
También es posible usar expresiones:
<?php db_merge('example') ->key(array('name' => $name)) ->fields(array( 'field1' => $value1, 'field2' => $value2, )) ->expression('field1', 'field1 + :inc', array(':inc' => 1)) ->execute(); ?>
Este ejemplo incrementará el valor de field1
en 1 si la fila ya existe. Es útil para contadores. Si la fila no existe, se insertará con field1 = $value1
y field2 = $value2
.
Actualizar parcialmente (updateExcept)
<?php db_merge('example') ->key(array('name' => $name)) ->fields(array( 'field1' => $value1, 'field2' => $value2, )) ->updateExcept('field1') ->execute(); ?>
Este método permite excluir ciertos campos de la actualización si la fila ya existe. En este ejemplo, field1
se excluirá de la actualización pero se insertará normalmente si la fila no existe.
Prioridades
Para evitar conflictos en la definición de campos, se aplican las siguientes reglas:
- Si un campo se define con
expression()
, tiene prioridad sobreupdate()
yupdateExcept()
. - Si se define en
update()
, se ignorará enupdateExcept()
. - Si se usa
update()
, solo esos campos se actualizarán.
Ten en cuenta que puedes definir una consulta sin sentido si ignoras estas reglas.