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!


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 .


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

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


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

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.