Come testare un'istruzione SQL Update prima di eseguirla?


96

In alcuni casi, l'esecuzione di un'istruzione UPDATE in produzione può salvare la giornata. Tuttavia un aggiornamento borked può essere peggiore del problema iniziale.

A parte l'utilizzo di un database di prova, quali sono le opzioni per dire cosa farà un'istruzione di aggiornamento prima di eseguirla?

Risposte:


52

Oltre a utilizzare una transazione come ha detto Imad (che dovrebbe essere comunque obbligatorio), puoi anche fare un controllo di integrità su quali righe sono interessate eseguendo una selezione utilizzando la stessa clausola WHERE dell'UPDATE.

Quindi, se UPDATE è

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

Quanto segue ti mostrerà quali righe verranno aggiornate:

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

1
Quindi utilizzare le transazioni è meglio per controllare i dati. Supponendo che voglia controllare il risultato, concludo che la sua affermazione è più complessa di una "barra SET = 42", quindi durante la sua sessione sarà in grado di effettuare diverse query per testare il set di dati risultante ...
Imad Moqaddem

3
@ImadMoqaddem: sono d'accordo ed è per questo che ho scritto " Oltre a usare una transazione come ha detto Imad "
a_horse_with_no_name

E se il FOREIGN KEY UPDATE CASCADEtuo sql fallisce
Green

@ Green: cosa intendi con "fallire"?
a_horse_with_no_name

73

E le transazioni? Hanno la funzione ROLLBACK.

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

Per esempio:

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

Risposta alla domanda di @rickozoe di seguito:

In generale queste righe non verranno eseguite come una volta. In PHP potresti scrivere qualcosa del genere (forse un po 'più pulito, ma volevo rispondere velocemente ;-)):

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

Un altro modo sarebbe usare variabili MySQL (vedi https://dev.mysql.com/doc/refman/5.7/en/user-variables.htm l e 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;

Ma suggerirei di utilizzare i wrapper del linguaggio disponibili nel tuo linguaggio di programmazione preferito.


1
Ciò avrà risultati imprevisti con transazioni nidificate.
focaccine

Puoi fare un esempio?
Marcel Lange

@JCM e altri, come puoi sapere se ha successo l'istruzione di aggiornamento ha esito positivo sulla riga 3 in modo da poter eseguire il commit e il rollback?
ricko zoe

56

Commit automatico disattivato ...

MySQL

set autocommit=0;

Imposta l'autommit per la sessione corrente.

Esegui la tua istruzione, vedi cosa è cambiato e poi esegui il rollback se è sbagliato o ti impegni se è quello che ti aspettavi!

MODIFICA: il vantaggio di utilizzare le transazioni invece di eseguire query di selezione è che puoi controllare più facilmente il set risultante.


4
@dystroy: ogni DBMS sensibile supporta le transazioni.
a_horse_with_no_name

7
Ricorda solo di eseguire il commit o il rollback della transazione rapidamente, altrimenti rischi di bloccare altre transazioni e, nel peggiore dei casi, di bloccare la tua applicazione. Non è una buona idea eseguire la query, quindi pranzare e tornare per vedere i risultati! :-)
Gary McGill

@GaryMcGill: la transazione in sospeso (almeno nel DBMS moderno) bloccherebbe solo altre transazioni di scrittura .
a_horse_with_no_name

5
@dystroy: Sfortunatamente, MyISAM è utilizzato ovunque e non sono l'amministratore delegato.
static_rtti

1
Aggiunta dichiarazione SQL :)
Imad Moqaddem

11

So che questa è una ripetizione di altre risposte, ma ha un supporto emotivo per fare il passo in più per testare l'aggiornamento: D

Per l'aggiornamento di test, l'hash # è tuo amico.

Se hai una dichiarazione di aggiornamento come:

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

Hai hash UPDATE e SET per il test, quindi li hash di nuovo in:

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

Funziona per semplici affermazioni.

Un'ulteriore soluzione praticamente obbligatoria è quella di ottenere una copia (duplicato di backup), ogni volta che si utilizza l'aggiornamento su una tabella di produzione. Phpmyadmin> operazioni> copia: table_yearmonthday. Ci vogliono solo pochi secondi per tabelle <= 100M.


5

Non una risposta diretta, ma ho visto molte situazioni di dati di produzione borked che avrebbero potuto essere evitate digitando WHEREprima la clausola ! A volte un WHERE 1 = 0può aiutare anche a mettere insieme una dichiarazione di lavoro in sicurezza. E guardare un piano di esecuzione stimato, che stimerà le righe interessate, può essere utile. Oltre a ciò, in una transazione che ripristini come altri hanno detto.


2
@SystemParadox - niente, anche se WHERE 1 = 0è più portabile se qualcuno si imbatte in questo che sta lavorando con un DBMS diverso. Ad esempio, SQL Server non accetterà WHERE FALSE.
David M

2

In questi casi che vuoi testare, è una buona idea concentrarti solo sui valori di colonna correnti e sui valori di colonna che verranno aggiornati a breve .

Dai un'occhiata al seguente codice che ho scritto per aggiornare i prezzi 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

In questo modo confrontiamo chiaramente i valori già esistenti con i nuovi valori.


1

Esegui la query di selezione sulla stessa tabella con tutte le wherecondizioni applicate nella query di aggiornamento.


0

fanne uno SELECT,

come se tu avessi

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

convertirlo in

SELECT * FROM users WHERE name='jan'

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.