MySQL im abgesicherten Modus löschen

84

Ich habe einen Tischlehrer und möchte die Datensätze löschen, deren Gehalt in einem Bereich liegt. Eine intuitive Methode ist wie folgt:

delete from instructor where salary between 13000 and 15000;

Im abgesicherten Modus kann ich einen Datensatz jedoch nicht löschen, ohne einen Primärschlüssel (ID) anzugeben.

Also schreibe ich folgendes SQL:

delete from instructor where ID in (select ID from instructor where salary between 13000 and 15000);

Es liegt jedoch ein Fehler vor:

You can't specify target table 'instructor' for update in FROM clause

Ich bin verwirrt, weil wenn ich schreibe

select * from instructor where ID in (select ID from instructor where salary between 13000 and 15000);

es erzeugt keinen Fehler.

Meine Frage ist:

  1. Was bedeutet diese Fehlermeldung wirklich und warum ist mein Code falsch?
  2. Wie schreibe ich diesen Code neu, damit er im abgesicherten Modus funktioniert?

Vielen Dank!

Roland Luo
quelle
Wollten Sie den abgesicherten Modus aktiviert lassen? und benutzt du mySql workbench?
Schreiben Sie
Die Antwort auf beide Fragen lautet Ja. Und ich bin überrascht, dass beim Löschen von Datensätzen in MySQL-Datenbanken ohne PK mit jdbc kein Fehler auftritt. Der abgesicherte Modus ist also nur für die MySQL-Workbench?
Roland Luo
1
nein - ich habe gefragt, denn wenn Sie es in der mySQL-Workbench ausschalten wollten, hätte ich Ihnen sagen können, wie. Persönlich arbeite ich damit ... Ausweise zu haben ist sehr sicherheitsrelevant - aber in
Bezug auf die

Antworten:

217

Beim Googeln scheint die beliebte Antwort " Schalten Sie einfach den abgesicherten Modus aus" zu sein :

SET SQL_SAFE_UPDATES = 0;
DELETE FROM instructor WHERE salary BETWEEN 13000 AND 15000;
SET SQL_SAFE_UPDATES = 1;

Wenn ich ehrlich bin, kann ich nicht sagen, dass ich es mir jemals zur Gewohnheit gemacht habe, im abgesicherten Modus zu laufen. Trotzdem bin ich mit dieser Antwort nicht ganz zufrieden, da nur davon ausgegangen wird, dass Sie Ihre Datenbankkonfiguration jedes Mal ändern sollten, wenn Sie auf ein Problem stoßen.

Ihre zweite Abfrage befindet sich also näher an der Marke, stößt jedoch auf ein anderes Problem: MySQL wendet einige Einschränkungen auf Unterabfragen an. Eine davon ist, dass Sie eine Tabelle nicht ändern können, während Sie sie in einer Unterabfrage auswählen.

Zitat aus dem MySQL-Handbuch, Einschränkungen für Unterabfragen :

Im Allgemeinen können Sie eine Tabelle nicht ändern und in einer Unterabfrage aus derselben Tabelle auswählen. Diese Einschränkung gilt beispielsweise für Anweisungen der folgenden Formen:

DELETE FROM t WHERE ... (SELECT ... FROM t ...);
UPDATE t ... WHERE col = (SELECT ... FROM t ...);
{INSERT|REPLACE} INTO t (SELECT ... FROM t ...);

Ausnahme: Das vorstehende Verbot gilt nicht, wenn Sie eine Unterabfrage für die geänderte Tabelle in der FROM-Klausel verwenden. Beispiel:

UPDATE t ... WHERE col = (SELECT * FROM (SELECT ... FROM t...) AS _t ...);

Hier wird das Ergebnis der Unterabfrage in der FROM-Klausel als temporäre Tabelle gespeichert, sodass die relevanten Zeilen in t zum Zeitpunkt der Aktualisierung auf t bereits ausgewählt wurden.

Das letzte bisschen ist deine Antwort. Wählen Sie Ziel-IDs in einer temporären Tabelle aus und löschen Sie sie, indem Sie auf die IDs in dieser Tabelle verweisen:

DELETE FROM instructor WHERE id IN (
  SELECT temp.id FROM (
    SELECT id FROM instructor WHERE salary BETWEEN 13000 AND 15000
  ) AS temp
);

SQLFiddle-Demo .

Rutter
quelle
6
Vielen Dank für Ihre Erklärung! Ich habe jedoch Ihren Code in der MySQL-Workbench ausprobiert und es stand immer noch "Sie verwenden den sicheren Aktualisierungsmodus und Sie haben versucht, eine Tabelle ohne ein WHERE zu aktualisieren, das eine KEY-Spalte verwendet".
Roland Luo
Das ist unerwartet. Ist Ihr Primärschlüssel unter einem anderen Namen? Ich stelle fest, dass Ihre Frage darauf hinweist, dass sie benannt ist ID, während meine Antwort verwendet id.
Rutter
Ja, ich ändere es in ID und es funktioniert nicht. Ich habe versucht , löschen von Instruktor wo ID = ‚1‘ und es funktioniert , so dass die ID der Primärschlüssel
roland luo
1
@rolandluo Ich weiß, es ist lange her, aber ich bin gespannt, ob Sie jemals eine Problemumgehung gefunden haben. Offensichtlich hat diese Methode unter anderen Umständen funktioniert, daher frage ich mich, warum Ihr Fall anders ist. Vielleicht etwas Spezielles für Ihren Server oder Ihre Version?
Rutter
19

Sie können MySQL dazu verleiten, zu glauben, dass Sie tatsächlich eine Primärschlüsselspalte angeben. Auf diese Weise können Sie den abgesicherten Modus "überschreiben".

Angenommen, Sie haben eine Tabelle mit einem automatisch inkrementierenden numerischen Primärschlüssel, können Sie Folgendes tun:

DELETE FROM tbl WHERE id <> 0
Hugo Zink
quelle
12

Deaktivieren des abgesicherten Modus in der MySQL-Workbench 6.3.4.0

Menü Bearbeiten => Einstellungen => SQL-Editor: Anderer Abschnitt: Klicken Sie auf "Sichere Updates" ..., um die Option zu deaktivieren

Workbench-Einstellungen

Peter B.
quelle
2
"Wie schreibe ich diesen Code neu, damit er im abgesicherten Modus funktioniert ?" ==> Ihre Antwort sagt, wie man den abgesicherten Modus deaktiviert;)
ByteHamster
2
Entschuldigung, ich habe die Frage völlig falsch verstanden. Ich habe dieses Thema gefunden, als ich mit der MySQL-Workbench nicht aus Tabellen löschen konnte, und es gab eine ähnliche Frage in einem Kommentar mit der MySQL-Workbench, aber ich kann keine Kommentare erstellen. Ich dachte, dass es ein guter Ort wäre, um dies hier als zukünftige Referenz zu schreiben ...
Peter B
0

Ich habe eine viel einfachere Lösung, sie funktioniert für mich. Es ist auch eine Problemumgehung, kann aber verwendet werden und Sie müssen Ihre Einstellungen nicht ändern. Ich gehe davon aus, dass Sie einen Wert verwenden können, der niemals vorhanden sein wird, und ihn dann in Ihrer WHERE-Klausel verwenden

DELETE FROM MyTable WHERE MyField IS_NOT_EQUAL AnyValueNoItemOnMyFieldWillEverHave

Ich mag diese Lösung auch nicht so sehr, deshalb bin ich hier, aber sie funktioniert und es scheint besser zu sein als das, was beantwortet wurde

Joaq
quelle