Błąd MySQL 1093 - nie można określić tabeli docelowej dla aktualizacji w klauzuli FROM
Mam tabelę story_category
w mojej bazie danych z uszkodzonymi wpisami. Następne zapytanie zwraca uszkodzone wpisy:
SELECT *
FROM story_category
WHERE category_id NOT IN (
SELECT DISTINCT category.id
FROM category INNER JOIN
story_category ON category_id=category.id);
Próbowałem je usunąć:
DELETE FROM story_category
WHERE category_id NOT IN (
SELECT DISTINCT category.id
FROM category
INNER JOIN story_category ON category_id=category.id);
Ale dostaję następny błąd:
Jak mogę to przezwyciężyć?#1093 - nie można określić docelowej tabeli 'story_category' dla aktualizacji w klauzuli FROM
16 answers
Aktualizacja: ta odpowiedź obejmuje ogólną klasyfikację błędów. Aby uzyskać bardziej szczegółową odpowiedź na temat tego, jak najlepiej poradzić sobie z dokładnym zapytaniem OP, zobacz inne odpowiedzi na to pytanie
W MySQL nie można modyfikować tej samej tabeli, której używasz w części SELECT.
Zachowanie to udokumentowane jest na:
http://dev.mysql.com/doc/refman/5.6/en/update.html
Może możesz po prostu dołączyć stół do siebie
Jeśli logika jest na tyle prosta, aby zmień kształt zapytania, utrać zapytanie podrzędne i dołącz tabelę do siebie, stosując odpowiednie kryteria wyboru. Spowoduje to, że MySQL będzie postrzegał tabelę jako dwie różne rzeczy, co pozwoli na wprowadzenie destrukcyjnych zmian.
UPDATE tbl AS a
INNER JOIN tbl AS b ON ....
SET a.col = b.col
Alternatywnie, spróbuj zagnieżdżać zapytanie podrzędne głębiej w klauzuli from ...
Jeśli absolutnie potrzebujesz subquery, jest obejście, ale to brzydka z kilku powodów, w tym wydajność:
UPDATE tbl SET col = (
SELECT ... FROM (SELECT.... FROM) AS x);
Zagnieżdżone zapytanie podrzędne w FROM klauzula tworzy implicit temporary Tabela , więc nie liczy się jako ta sama tabela, którą aktualizujesz.
... ale uważaj na optymalizator zapytań
Uważaj jednak, że od MySQL 5.7.6 i dalej, optymalizator może zoptymalizować zapytanie podrzędne i nadal dać ci błąd. Na szczęście zmienna optimizer_switch
może być użyta do wyłączenia tego zachowania; chociaż nie polecam tego zrobić jako coś więcej niż krótkoterminowa poprawka lub małe jednorazowe zadania.
SET optimizer_switch = 'derived_merge=off';
dzięki Peter V. Mørch za tę radę w komentarzach.
Przykładowa technika pochodzi od barona Schwartza, pierwotnie opublikowana w Nabble [11]}, sparafrazowana i rozszerzona tutaj.Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 12:02:45
NexusRex dostarczył bardzo dobre rozwiązanie do usuwania za pomocą join z tej samej tabeli.
Jeśli to zrobisz:
DELETE FROM story_category
WHERE category_id NOT IN (
SELECT DISTINCT category.id AS cid FROM category
INNER JOIN story_category ON category_id=category.id
)
Dostaniesz błąd.
Ale jeśli zawijasz warunek w jeszcze jeden Wybierz:
DELETE FROM story_category
WHERE category_id NOT IN (
SELECT cid FROM (
SELECT DISTINCT category.id AS cid FROM category
INNER JOIN story_category ON category_id=category.id
) AS c
)
To by dobrze zrobiło!!
Explanation: optymalizator zapytań wykonuje pochodna optymalizacja łączenia dla pierwszego zapytania (co powoduje, że nie powiodło się z błędem), ale drugie zapytanie nie kwalifikuje się do pochodnej optymalizacji merge . Dlatego optymalizator jest zmuszony najpierw wykonać zapytanie podrzędne.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-09-09 16:10:32
inner join
w zapytaniu podrzędnym jest niepotrzebne. Wygląda na to, że chcesz usunąć wpisy z story_category
, Gdzie category_id
nie znajduje się w tabeli category
.
Zrób to:
DELETE FROM story_category
WHERE category_id NOT IN (
SELECT DISTINCT category.id
FROM category);
Zamiast tego:
DELETE FROM story_category
WHERE category_id NOT IN (
SELECT DISTINCT category.id
FROM category INNER JOIN
story_category ON category_id=category.id);
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-05-31 09:37:53
Ostatnio musiałem zaktualizować rekordy w tej samej tabeli zrobiłem to jak poniżej:
UPDATE skills AS s, (SELECT id FROM skills WHERE type = 'Programming') AS p
SET s.type = 'Development'
WHERE s.id = p.id;
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-12-20 10:48:20
If you can ' t do
UPDATE table SET a=value WHERE x IN
(SELECT x FROM table WHERE condition);
Ponieważ jest to ta sama tabela, możesz trick and do:
UPDATE table SET a=value WHERE x IN
(SELECT * FROM (SELECT x FROM table WHERE condition) as t)
[update or delete or whatever]
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-04-25 11:59:56
DELETE FROM story_category
WHERE category_id NOT IN (
SELECT cid FROM (
SELECT DISTINCT category.id AS cid FROM category INNER JOIN story_category ON category_id=category.id
) AS c
)
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-12-23 20:03:08
To jest to, co zrobiłem, aby zaktualizować wartość kolumny Priorytetu o 1, jeśli jest >=1 w tabeli i w jej klauzuli WHERE, używając zapytania podrzędnego w tej samej tabeli, aby upewnić się, że co najmniej jeden wiersz zawiera Priorytet=1 (ponieważ był to warunek do sprawdzenia podczas aktualizacji):
UPDATE My_Table
SET Priority=Priority + 1
WHERE Priority >= 1
AND (SELECT TRUE FROM (SELECT * FROM My_Table WHERE Priority=1 LIMIT 1) as t);
Wiem, że jest trochę brzydki, ale działa dobrze.Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-09-02 07:31:45
Najprostszym sposobem na to jest użycie aliasu tabeli, gdy odwołujesz się do nadrzędnej tabeli zapytań wewnątrz podrzędnego zapytania.
Przykład:
insert into xxx_tab (trans_id) values ((select max(trans_id)+1 from xxx_tab));
Zmień na:
insert into xxx_tab (trans_id) values ((select max(P.trans_id)+1 from xxx_tab P));
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-01-11 02:14:39
Dla konkretnego zapytania, które OP próbuje osiągnąć, idealnym i najbardziej efektywnym sposobem na to jest nieużywanie w ogóle zapytań podrzędnych.
Oto LEFT JOIN
wersje dwóch zapytań OP:
SELECT s.*
FROM story_category s
LEFT JOIN category c
ON c.id=s.category_id
WHERE c.id IS NULL;
Uwaga: DELETE s
ogranicza operacje usuwania do Tabeli story_category
.
dokumentacja
DELETE s
FROM story_category s
LEFT JOIN category c
ON c.id=s.category_id
WHERE c.id IS NULL;
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-04-09 19:05:15
Można wstawić ID żądanych wierszy do tabeli tymczasowej, a następnie usunąć wszystkie wiersze, które znajdują się w tej tabeli.
Co @Cheekysoft miał na myśli, robiąc to w dwóch krokach.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-09-05 10:25:35
Zgodnie z składnią aktualizacji Mysql podlinkowaną przez @ CheekySoft, jest napisane na dole.
Obecnie nie można zaktualizować tabeli i wybrać z tej samej tabeli w zapytaniu podrzędnym.
Domyślam się, że usuwasz z store_category, jednocześnie wybierając z niego w Unii.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-01-08 13:18:46
Jeśli coś nie działa, przy wchodzeniu przez drzwi wejściowe, weź tylne drzwi:
drop table if exists apples;
create table if not exists apples(variety char(10) primary key, price int);
insert into apples values('fuji', 5), ('gala', 6);
drop table if exists apples_new;
create table if not exists apples_new like apples;
insert into apples_new select * from apples;
update apples_new
set price = (select price from apples where variety = 'gala')
where variety = 'fuji';
rename table apples to apples_orig;
rename table apples_new to apples;
drop table apples_orig;
Jest szybki. Im większe DANE, tym lepiej.Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-03-29 02:26:30
Spróbuj zapisać wynik instrukcji Select w osobnej zmiennej, a następnie użyj jej do zapytania delete.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-05-31 11:35:18
Spróbuj tego
DELETE FROM story_category
WHERE category_id NOT IN (
SELECT DISTINCT category.id
FROM (SELECT * FROM STORY_CATEGORY) sc;
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-01-23 01:14:45
A co z tym zapytaniem mam nadzieję, że pomoże
DELETE FROM story_category LEFT JOIN (SELECT category.id FROM category) cat ON story_category.id = cat.id WHERE cat.id IS NULL
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-11 01:55:03
Jeśli chodzi o problem, chcesz usunąć wiersze w story_category
, które nie istnieją w category
.
Oto oryginalne zapytanie, aby zidentyfikować wiersze do usunięcia:
SELECT *
FROM story_category
WHERE category_id NOT IN (
SELECT DISTINCT category.id
FROM category INNER JOIN
story_category ON category_id=category.id
);
Łączenie NOT IN
z zapytaniem podrzędnym, które JOIN
wydaje się niepotrzebnie zawiłe. Można to wyrazić w bardziej prosty sposób za pomocą not exists
i skorelowanej podquery:
select sc.*
from story_category sc
where not exists (select 1 from category c where c.id = sc.category_id);
Teraz łatwo przekształcić to w delete
stwierdzenie:
delete from story_category
where not exists (select 1 from category c where c.id = story_category.category_id);
To zapytanie uruchomi się na dowolnym MySQL wersji, jak również w większości innych baz danych, które znam.
-- set-up
create table story_category(category_id int);
create table category (id int);
insert into story_category values (1), (2), (3), (4), (5);
insert into category values (4), (5), (6), (7);
-- your original query to identify offending rows
SELECT *
FROM story_category
WHERE category_id NOT IN (
SELECT DISTINCT category.id
FROM category INNER JOIN
story_category ON category_id=category.id);
| category_id | | ----------: | | 1 | | 2 | | 3 |
-- a functionally-equivalent, simpler query for this
select sc.*
from story_category sc
where not exists (select 1 from category c where c.id = sc.category_id)
| category_id | | ----------: | | 1 | | 2 | | 3 |
-- the delete query
delete from story_category
where not exists (select 1 from category c where c.id = story_category.category_id);
-- outcome
select * from story_category;
| category_id | | ----------: | | 4 | | 5 |
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-04-10 10:46:12