mysql usuń w trybie awaryjnym

94

Mam instruktora tabeli i chcę usunąć rekordy, które mają wynagrodzenie w przedziale. Intuicyjny sposób wygląda tak:

delete from instructor where salary between 13000 and 15000;

Jednak w trybie awaryjnym nie mogę usunąć rekordu bez podania klucza podstawowego (ID).

Więc piszę następujący sql:

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

Jednak jest błąd:

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

Jestem zdezorientowany, ponieważ kiedy piszę

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

nie powoduje błędu.

Moje pytanie brzmi:

  1. co naprawdę oznacza ten komunikat o błędzie i dlaczego mój kod jest nieprawidłowy?
  2. jak przepisać ten kod, aby działał w trybie awaryjnym?

Dzięki!

roland luo
źródło
czy chcesz, aby tryb bezpieczny był włączony? i czy używasz mySql Workbench?
napisać
odpowiedź na oba pytania brzmi: tak. I jestem zaskoczony, że kiedy użyłem jdbc do usunięcia rekordów w bazach danych mysql bez PK, nie powoduje to błędu. Czyli tryb bezpieczny jest przeznaczony tylko dla środowiska roboczego mysql?
roland luo
1
nie - pytałem, bo gdybyś chciał to wyłączyć w środowisku roboczym mySQL, mógłbym ci powiedzieć, jak to zrobić. Osobiście pracuję z tym poza ... posiadanie identyfikatorów jest bardzo bezpieczne z
punktu widzenia

Odpowiedzi:

235

W wyszukiwarce Google popularną odpowiedzią wydaje się być „po prostu wyłącz tryb awaryjny” :

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

Szczerze mówiąc, nie mogę powiedzieć, żebym kiedykolwiek miał w zwyczaju biegać w trybie awaryjnym. Mimo to nie jestem do końca zadowolony z tej odpowiedzi, ponieważ zakłada ona po prostu, że powinieneś zmieniać konfigurację bazy danych za każdym razem, gdy napotkasz problem.

Zatem twoje drugie zapytanie jest bliżej znaku, ale napotyka inny problem: MySQL nakłada kilka ograniczeń na podzapytania, a jednym z nich jest to, że nie możesz modyfikować tabeli podczas wybierania jej w podzapytaniu.

Cytowanie z podręcznika MySQL, Restrictions on Subqueries :

Zasadniczo nie można modyfikować tabeli i wybierać z tej samej tabeli w podzapytaniu. Na przykład to ograniczenie dotyczy oświadczeń w następujących formach:

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

Wyjątek: powyższy zakaz nie ma zastosowania, jeśli używasz podzapytania dla zmodyfikowanej tabeli w klauzuli FROM. Przykład:

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

Tutaj wynik z podzapytania w klauzuli FROM jest przechowywany jako tabela tymczasowa, więc odpowiednie wiersze w t zostały już wybrane przed dokonaniem aktualizacji do t.

Ta ostatnia odpowiedź to twoja odpowiedź. Wybierz identyfikatory docelowe w tabeli tymczasowej, a następnie usuń, odwołując się do identyfikatorów w tej tabeli:

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

Demo SQLFiddle .

rutter
źródło
6
Dziękuję za wyjaśnienie! Jednak wypróbowałem Twój kod w środowisku roboczym mysql i nadal wyświetlał się komunikat „Używasz bezpiecznego trybu aktualizacji i próbowałeś zaktualizować tabelę bez GDZIE, która używa kolumny KEY”.
roland luo
To nieoczekiwane. Czy Twój klucz podstawowy ma inną nazwę? Zauważyłem, że twoje pytanie wydaje się wskazywać, że zostało nazwane ID, podczas gdy moja odpowiedź używa id.
rutter
Tak, zmieniam to na ID i nie działa. Próbowałem usunąć z instruktora, gdzie ID = '1' i działa, więc ID jest kluczem podstawowym
roland luo
1
@rolandluo Wiem, że minęło dużo czasu, ale jestem ciekawy, czy kiedykolwiek znalazłeś obejście. Oczywiście ta metoda zadziałała w innych okolicznościach, więc zastanawiam się, dlaczego twój przypadek jest inny. Może coś konkretnego dla Twojego serwera lub wersji?
rutter
19

Możesz oszukać MySQL, aby pomyślał, że faktycznie określasz kolumnę klucza podstawowego. Pozwala to na „przesłonięcie” trybu awaryjnego.

Zakładając, że masz tabelę z automatycznie zwiększającym się liczbowym kluczem podstawowym, możesz wykonać następujące czynności:

DELETE FROM tbl WHERE id <> 0
Hugo Zink
źródło
12

Wyłączanie trybu awaryjnego w środowisku roboczym MySQL 6.3.4.0

Menu Edytuj => Preferencje => Edytor SQL: Sekcja Inne: kliknij „Bezpieczne aktualizacje” ... aby odznaczyć opcję

Preferencje środowiska roboczego

Peter B.
źródło
2
„jak przepisać ten kod, aby działał w trybie awaryjnym ?” ==> Twoja odpowiedź mówi, jak wyłączyć tryb awaryjny;)
ByteHamster
2
Przepraszam, całkowicie źle zrozumiałem pytanie. Znalazłem ten temat, gdy nie udało mi się usunąć z tabel za pomocą Mysql workbench, a podobne pytanie było w komentarzu z mysql workbench, ale nie mogę tworzyć komentarzy. Pomyślałem, że byłoby to dobre miejsce, aby napisać to tutaj na przyszłość ...
Peter B
0

Mam znacznie prostsze rozwiązanie, działa dla mnie; jest to również obejście, ale może być użyteczne i nie musisz zmieniać ustawień. Zakładam, że możesz użyć wartości, której nigdy nie będzie, a następnie użyj jej w swojej klauzuli WHERE

USUŃ Z MyTable WHERE MyField IS_NOT_EQUAL AnyValueNoItemOnMyFieldWillEverHave

To rozwiązanie też mi się nie podoba, dlatego tu jestem, ale działa i wydaje się lepsze niż ta, na którą odpowiedziano

Joaq
źródło