Wie teste ich eine SQL Update-Anweisung, bevor ich sie ausführe?

93

In einigen Fällen kann das Ausführen einer UPDATE-Anweisung in der Produktion den Tag retten. Ein falsches Update kann jedoch schlimmer sein als das ursprüngliche Problem.

Welche Optionen stehen zur Verfügung, um zu bestimmen, was eine Update-Anweisung vor der Ausführung tun soll, ohne eine Testdatenbank zu verwenden?

static_rtti
quelle

Antworten:

48

Zusätzlich zur Verwendung einer Transaktion, wie Imad gesagt hat (was ohnehin obligatorisch sein sollte), können Sie auch eine Überprüfung der Integrität durchführen, welche Zeilen betroffen sind, indem Sie eine Auswahl mit derselben WHERE-Klausel wie UPDATE ausführen.

Also, wenn Sie UPDATE ist

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

Folgendes zeigt Ihnen, welche Zeilen aktualisiert werden:

SELECT *
FROM foo
WHERE col1 = 1
  AND col2 = 'foobar';
ein Pferd ohne Name
quelle
1
Die Verwendung von Transaktionen ist dann besser, um Daten zu überprüfen. Angenommen, er möchte das Ergebnis überprüfen, so schließe ich, dass seine Aussage komplexer ist als ein 'SET-Balken = 42', sodass er innerhalb seiner Sitzung mehrere Abfragen durchführen kann, um den resultierenden Datensatz zu testen ...
Imad Moqaddem
3
@ ImadMoqaddem: Ich stimme zu und deshalb schrieb ich " Abgesehen von der Verwendung einer Transaktion, wie Imad sagte "
a_horse_with_no_name
Und wenn Sie FOREIGN KEY UPDATE CASCADEIhre SQL-Fehler haben
Green
@Green: Was meinst du mit "scheitern"?
a_horse_with_no_name
73

Was ist mit Transaktionen? Sie haben die ROLLBACK-Funktion.

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

Beispielsweise:

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

Antwort auf die Frage von @rickozoe unten:

Im Allgemeinen werden diese Zeilen nicht einmal ausgeführt. In PHP zB würden Sie so etwas schreiben (vielleicht etwas sauberer, wollten aber schnell antworten ;-)):

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

Eine andere Möglichkeit wäre die Verwendung von MySQL-Variablen (siehe https://dev.mysql.com/doc/refman/5.7/en/user-variables.htm l und 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;

Ich würde jedoch empfehlen, die in Ihrer bevorzugten Programmiersprache verfügbaren Sprachumschläge zu verwenden.

Marcel Lange
quelle
1
Dies führt zu unerwarteten Ergebnissen bei verschachtelten Transaktionen.
Scones
Können Sie bitte ein Beispiel geben?
Marcel Lange
@JCM und andere, wie können Sie feststellen, ob die Update-Anweisung in Zeile 3 erfolgreich ist, damit Sie ein Commit durchführen und ein Rollback durchführen können?
Ricko Zoe
55

Autocommit AUS ...

MySQL

set autocommit=0;

Dadurch wird die automatische Festschreibung für die aktuelle Sitzung deaktiviert.

Sie führen Ihre Anweisung aus, sehen, was sie geändert hat, und führen dann einen Rollback durch, wenn sie falsch ist, oder legen fest, wenn sie Ihren Erwartungen entspricht!

BEARBEITEN: Der Vorteil der Verwendung von Transaktionen anstelle der Ausführung einer Auswahlabfrage besteht darin, dass Sie die resultierende Menge einfacher überprüfen können.

Imad Moqaddem
quelle
4
@dystroy: Jedes sinnvolle DBMS unterstützt Transaktionen.
a_horse_with_no_name
7
Denken Sie daran, die Transaktion schnell festzuschreiben oder zurückzusetzen, da Sie sonst das Risiko eingehen, andere Transaktionen zu blockieren - und im schlimmsten Fall Ihre Anwendung zum Erliegen zu bringen. Es ist keine gute Idee, die Abfrage auszuführen, dann zu Mittag zu essen und dann zurück zu kommen, um die Ergebnisse zu sehen! :-)
Gary McGill
@GaryMcGill: die anstehende Transaktion nur (in der modernen DBMS mindestens) würden andere blockieren Schreib obwohl Transaktionen.
a_horse_with_no_name
5
@dystroy: Leider wird MyISAM überall verwendet und ich bin nicht der DBA.
static_rtti
1
SQL-Anweisung hinzugefügt :)
Imad Moqaddem
11

Ich weiß, dass dies eine Wiederholung anderer Antworten ist, aber es hat eine gewisse emotionale Unterstützung, um den zusätzlichen Schritt zum Testen des Updates zu unternehmen: D.

Zum Testen des Updates ist Hash # Ihr Freund.

Wenn Sie eine Update-Anweisung haben wie:

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

Sie hashen UPDATE und SET zum Testen und hashen sie dann wieder ein:

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

Es funktioniert für einfache Aussagen.

Eine zusätzliche, praktisch obligatorische Lösung besteht darin, eine Kopie (Sicherungsduplikat) zu erhalten, wenn ein Update für eine Produktionstabelle verwendet wird. Phpmyadmin> Operationen> Kopie: table_yearmonthday. Für Tabellen <= 100M dauert es nur wenige Sekunden.

Johan
quelle
5

Keine direkte Antwort, aber ich habe viele Situationen mit fehlerhaften Produktdaten gesehen, die hätten vermieden werden können, wenn man zuerst die WHEREKlausel eingegeben hätte ! Manchmal WHERE 1 = 0kann a auch bei der sicheren Zusammenstellung einer Arbeitserklärung helfen. Ein Blick auf einen geschätzten Ausführungsplan, der die betroffenen Zeilen schätzt, kann hilfreich sein. Darüber hinaus in einer Transaktion, die Sie zurücksetzen, wie andere gesagt haben.

David M.
quelle
2
@SystemParadox - nichts WHERE 1 = 0ist jedoch portabler, wenn jemand darauf stößt, der mit einem anderen DBMS arbeitet. Beispielsweise akzeptiert SQL Server nicht WHERE FALSE.
David M
2

In diesen Fällen, die Sie testen möchten, empfiehlt es sich, sich nur auf aktuelle Spaltenwerte und in Kürze zu aktualisierende Spaltenwerte zu konzentrieren.

Bitte schauen Sie sich den folgenden Code an, den ich geschrieben habe, um die WHMCS-Preise zu aktualisieren:

# 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

Auf diese Weise vergleichen wir bereits vorhandene Werte klar mit neuen Werten.

Mohammad Naji
quelle
1

Führen Sie eine Auswahlabfrage in derselben Tabelle mit allen whereBedingungen aus, die Sie in der Aktualisierungsabfrage anwenden.

Manurajhada
quelle
0

mach ein SELECTdaraus,

wie wenn du hast

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

konvertiere es in

SELECT * FROM users WHERE name='jan'

EaterOfCode
quelle