¿Cómo probar una instrucción SQL Update antes de ejecutarla?


96

En algunos casos, ejecutar una instrucción UPDATE en producción puede salvar el día. Sin embargo, una actualización defectuosa puede ser peor que el problema inicial.

Aparte de usar una base de datos de prueba, ¿cuáles son las opciones para saber qué hará una declaración de actualización antes de ejecutarla?

Respuestas:


52

Además de usar una transacción como ha dicho Imad (que debería ser obligatorio de todos modos), también puede hacer una verificación de cordura qué filas se ven afectadas al ejecutar una selección usando la misma cláusula WHERE que la ACTUALIZACIÓN.

Entonces, si ACTUALIZA es

UPDATE foo
  SET bar = 42
WHERE col1 = 1
  AND col2 = 'foobar';

Lo siguiente le mostrará qué filas se actualizarán:

SELECT *
FROM foo
WHERE col1 = 1
  AND col2 = 'foobar';

1
Entonces, usar transacciones es mejor para verificar los datos. Suponiendo que quiera verificar el resultado, concluyo que su declaración es más compleja que una 'barra SET = 42', por lo que dentro de su sesión podrá realizar varias consultas para probar el conjunto de datos resultante ...
Imad Moqaddem

3
@ImadMoqaddem: Estoy de acuerdo y por eso escribí " Aparte de usar una transacción como dijo Imad "
a_horse_with_no_name

Y si tiene FOREIGN KEY UPDATE CASCADEsu sql falla
Verde

@Green: ¿Qué quieres decir con "fallar"?
a_horse_with_no_name

73

¿Qué pasa con las transacciones? Tienen la función ROLLBACK.

@ver https://dev.mysql.com/doc/refman/5.0/en/commit.html

Por ejemplo:

START TRANSACTION;
SELECT * FROM nicetable WHERE somthing=1;
UPDATE nicetable SET nicefield='VALUE' WHERE somthing=1;
SELECT * FROM nicetable WHERE somthing=1; #check

COMMIT;
# or if you want to reset changes 
ROLLBACK;

SELECT * FROM nicetable WHERE somthing=1; #should be the old value

Respuesta a la pregunta de @rickozoe a continuación:

En general, estas líneas no se ejecutarán como una vez. En PHP fe escribirías algo así (tal vez un poco más limpio, pero quería responder rápido ;-)):

$MysqlConnection->query('START TRANSACTION;');
$erg = $MysqlConnection->query('UPDATE MyGuests SET lastname='Doe' WHERE id=2;');
if($erg)
    $MysqlConnection->query('COMMIT;');
else
    $MysqlConnection->query('ROLLBACK;');

Otra forma sería usar Variables MySQL (consulte https://dev.mysql.com/doc/refman/5.7/en/user-variables.htm ly https://stackoverflow.com/a/18499823/1416909 ):

# do some stuff that should be conditionally rollbacked later on

SET @v1 := UPDATE MyGuests SET lastname='Doe' WHERE id=2;
IF(v1 < 1) THEN
    ROLLBACK;
ELSE
    COMMIT;
END IF;

Pero sugeriría usar los envoltorios de lenguaje disponibles en su lenguaje de programación favorito.


1
Esto tendrá resultados inesperados con transacciones anidadas.
bollos

¿Puede dar un ejemplo?
Marcel Lange

@JCM y otros, ¿cómo puede saber si tiene éxito la declaración de actualización en la línea 3 para que pueda comprometerse y revertir?
ricko zoe

56

Autocommit OFF ...

MySQL

set autocommit=0;

Activa la transmisión automática para la sesión actual.

Ejecuta su declaración, ve qué ha cambiado y luego retrocede si está mal o confirma si es lo que esperaba.

EDITAR: El beneficio de usar transacciones en lugar de ejecutar una consulta de selección es que puede verificar el conjunto resultante más fácilmente.


4
@dystroy: todo DBMS sensato admite transacciones.
a_horse_with_no_name

7
Solo recuerde confirmar o revertir la transacción rápidamente, o corre el riesgo de bloquear otras transacciones y, en el peor de los casos, detener su aplicación. No es una buena idea ejecutar la consulta, luego almorzar y luego volver para ver los resultados. :-)
Gary McGill

@GaryMcGill: la transacción pendiente (al menos en los DBMS modernos) solo bloquearía otras transacciones de escritura .
a_horse_with_no_name

5
@dystroy: Desafortunadamente, MyISAM se usa en todas partes y no soy el DBA.
static_rtti

1
Declaración SQL agregada :)
Imad Moqaddem

11

Sé que esta es una repetición de otras respuestas, pero tiene algo de apoyo emocional para dar el paso adicional para probar la actualización: D

Para probar la actualización, hash # es tu amigo.

Si tiene una declaración de actualización como:

UPDATE 
wp_history
SET history_by="admin"
WHERE
history_ip LIKE '123%'

Haces hash UPDATE y SET para pruebas, luego has hash de nuevo en:

SELECT * FROM
#UPDATE
wp_history
#SET history_by="admin"
WHERE
history_ip LIKE '123%'

Funciona para declaraciones simples.

Una solución adicional prácticamente obligatoria es obtener una copia (copia de seguridad duplicada), siempre que se utilice la actualización en una mesa de producción. Phpmyadmin> operaciones> copiar: table_yearmonthday. Solo toma unos segundos para tablas <= 100M.


5

No es una respuesta directa, pero he visto muchas situaciones fallidas de datos de prod que podrían haberse evitado escribiendo la WHEREcláusula primero . A veces, también WHERE 1 = 0puede ayudar a armar una declaración de trabajo de manera segura. Y mirar un plan de ejecución estimado, que estimará las filas afectadas, puede ser útil. Más allá de eso, en una transacción que revierte como han dicho otros.


2
@SystemParadox: nada, aunque WHERE 1 = 0es más portátil si alguien se encuentra con esto y está trabajando con un DBMS diferente. Por ejemplo, SQL Server no aceptará WHERE FALSE.
David M

2

En estos casos que desee probar, es una buena idea centrarse solo en los valores de columna actuales y en los valores de columna que se actualizarán pronto .

Por favor, eche un vistazo al siguiente código que escribí para actualizar los precios de WHMCS:

# UPDATE tblinvoiceitems AS ii

SELECT                        ###  JUST
    ii.amount AS old_value,   ###  FOR
    h.amount AS new_value     ###  TESTING
FROM tblinvoiceitems AS ii    ###  PURPOSES.

JOIN tblhosting AS h ON ii.relid = h.id
JOIN tblinvoices AS i ON ii.invoiceid = i.id

WHERE ii.amount <> h.amount   ### Show only updatable rows

# SET ii.amount = h.amount

De esta manera comparamos claramente los valores ya existentes con los valores nuevos.


1

Ejecute la consulta de selección en la misma tabla con todas las wherecondiciones que está aplicando en la consulta de actualización.


0

hacer una SELECT ,

como si tuvieras

UPDATE users SET id=0 WHERE name='jan'

convertirlo a

SELECT * FROM users WHERE name='jan'

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.