mysql elimina in modalità provvisoria


92

Ho un istruttore di tavolo e voglio eliminare i record che hanno lo stipendio in un intervallo.Un modo intuitivo è così:

delete from instructor where salary between 13000 and 15000;

Tuttavia, in modalità provvisoria, non è possibile eliminare un record senza fornire una chiave primaria (ID).

Quindi scrivo il seguente sql:

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

Tuttavia, c'è un errore:

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

Sono confuso perché quando scrivo

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

non produce un errore.

La mia domanda è:

  1. cosa significa veramente questo messaggio di errore e perché il mio codice è sbagliato?
  2. come riscrivere questo codice per farlo funzionare in modalità provvisoria?

Grazie!


vuoi mantenere attiva la modalità provvisoria? e stai usando mySql workbench?
wribit

la risposta ad entrambe le tue domande è sì. E sono sorpreso che quando ho usato jdbc per eliminare i record nei database mysql senza un PK, non produce un errore. Quindi la modalità provvisoria è solo per il workbench mysql?
roland luo

1
no - ti stavo chiedendo perché se avessi voluto spegnerlo nel workbench mySQL, avrei potuto dirti come. Personalmente lavoro senza ... dover avere ID è una grande sicurezza dal punto di vista della sicurezza, ma per quanto riguarda lo sviluppo, l'ho trovato un
problema

Risposte:


233

Cercando su Google, la risposta popolare sembra essere "disattiva la modalità provvisoria" :

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

Se devo essere sincero, non posso dire di aver mai preso l'abitudine di correre in modalità provvisoria. Tuttavia, non sono del tutto a mio agio con questa risposta poiché presume che dovresti cambiare la configurazione del tuo database ogni volta che incontri un problema.

Quindi, la tua seconda query è più vicina al segno, ma incontra un altro problema: MySQL applica alcune restrizioni alle sottoquery e una di queste è che non puoi modificare una tabella mentre selezioni da essa in una sottoquery.

Citando dal manuale MySQL, Restrizioni sulle sottoquery :

In generale, non è possibile modificare una tabella e selezionare dalla stessa tabella in una sottoquery. Ad esempio, questa limitazione si applica alle dichiarazioni delle seguenti forme:

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

Eccezione: il divieto precedente non si applica se si utilizza una sottoquery per la tabella modificata nella clausola FROM. Esempio:

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

Qui il risultato della sottoquery nella clausola FROM viene memorizzato come una tabella temporanea, quindi le righe pertinenti in t sono già state selezionate nel momento in cui ha luogo l'aggiornamento a t.

Quest'ultimo pezzo è la tua risposta. Seleziona gli ID di destinazione in una tabella temporanea, quindi elimina facendo riferimento agli ID in quella tabella:

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

Demo di SQLFiddle .


6
Grazie per la tua spiegazione! Tuttavia, ho provato il tuo codice in mysql workbench e ancora diceva "Stai utilizzando la modalità di aggiornamento sicuro e hai provato ad aggiornare una tabella senza un WHERE che utilizza una colonna KEY".
roland luo

È inaspettato. La tua chiave primaria ha un nome diverso? Ho notato che la tua domanda sembra indicare il nome ID, mentre la mia risposta usa id.
Rutter

Sì, lo cambio in ID e non funziona. Ho provato a eliminare dall'istruttore dove ID = '1' e funziona quindi l'ID è la chiave primaria
roland luo

1
@rolandluo So che è passato molto tempo, ma sono curioso di sapere se hai mai trovato una soluzione alternativa. Chiaramente questo metodo ha funzionato in altre circostanze, quindi mi chiedo perché il tuo caso sia diverso. Qualcosa di specifico per il tuo server o versione, forse?
Rutter

19

Puoi ingannare MySQL facendogli credere che stai effettivamente specificando una colonna chiave primaria. Ciò consente di "ignorare" la modalità provvisoria.

Supponendo che tu abbia una tabella con una chiave primaria numerica a incremento automatico, potresti fare quanto segue:

DELETE FROM tbl WHERE id <> 0

12

Disattivazione della modalità provvisoria in Mysql workbench 6.3.4.0

Menu Modifica => Preferenze => Editor SQL: sezione Altro: fare clic su "Aggiornamenti sicuri" ... per deselezionare l'opzione

Preferenze del banco di lavoro


2
"come riscrivere questo codice per farlo funzionare in modalità provvisoria ?" ==> La tua risposta spiega come disabilitare la modalità provvisoria;)
ByteHamster

2
Scusa, ho completamente frainteso la domanda. Ho trovato questo argomento quando non ero in grado di eliminare dalle tabelle con Mysql workbench, e c'era una domanda simile in un commento con mysql workbench, ma non posso creare commenti. Ho pensato che sarebbe stato un buon posto per scriverlo qui per riferimento futuro ...
Peter B

0

Ho una soluzione molto più semplice, funziona per me; è anche una soluzione alternativa, ma potrebbe essere utilizzabile e non è necessario modificare le impostazioni. Presumo che tu possa usare un valore che non sarà mai lì, quindi lo usi nella tua clausola WHERE

ELIMINA DA MyTable WHERE MyField IS_NOT_EQUAL AnyValueNoItemOnMyFieldWillEverHave

Neanche a me piace troppo quella soluzione, ecco perché sono qui, ma funziona e sembra migliore di quello a cui è stato risposto

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.