Ik heb een tabel story_category
in mijn database met corrupte gegevens. De volgende query retourneert de corrupte invoer:
SELECT *
FROM story_category
WHERE category_id NOT IN (
SELECT DISTINCT category.id
FROM category INNER JOIN
story_category ON category_id=category.id);
Ik heb geprobeerd ze te verwijderen door:
DELETE FROM story_category
WHERE category_id NOT IN (
SELECT DISTINCT category.id
FROM category
INNER JOIN story_category ON category_id=category.id);
Maar ik krijg de volgende foutmelding:
#1093 – U kunt de doeltabel ‘story_category’ niet specificeren voor update in de FROM-clausule
Hoe kan ik dit oplossen?
Antwoord 1, autoriteit 100%
Update: dit antwoord behandelt de algemene foutclassificatie. Voor een specifieker antwoord over hoe u de exacte vraag van de OP het beste kunt behandelen, zie andere antwoorden op deze vraag
In MySQL kunt u niet dezelfde tabel wijzigen die u in het SELECT-gedeelte gebruikt.
Dit gedrag is gedocumenteerd op:
http://dev.mysql.com/doc/refman/5.6/en /update.html
Misschien kun je gewoon aan tafel gaan zitten
Als de logica eenvoudig genoeg is om de query opnieuw vorm te geven, verliest u de subquery en voegt u de tabel aan zichzelf toe, waarbij u de juiste selectiecriteria gebruikt. Hierdoor ziet MySQL de tabel als twee verschillende dingen, waardoor destructieve veranderingen kunnen plaatsvinden.
UPDATE tbl AS a
INNER JOIN tbl AS b ON ....
SET a.col = b.col
U kunt ook proberen de subquery dieper in een from-clausule te nesten …
Als je de subquery absoluut nodig hebt, is er een tijdelijke oplossing, maar die is
lelijk om verschillende redenen, waaronder prestaties:
UPDATE tbl SET col = (
SELECT ... FROM (SELECT.... FROM) AS x);
De geneste subquery in de FROM-component creëert een impliciete tijdelijke
table, dus het telt niet als dezelfde tabel die u bijwerkt.
… maar pas op voor de query-optimizer
Pas echter op dat van MySQL 5.7.6en hoger, kan de optimizer de subquery optimaliseren en u nog steeds de fout geven. Gelukkig kan de variabele optimizer_switch
worden gebruikt om dit gedrag uit te schakelen; hoewel ik dit niet kan aanbevelen als iets meer dan een kortetermijnoplossing of voor kleine eenmalige taken.
SET optimizer_switch = 'derived_merge=off';
Met dank aan Peter V. Mørchvoor dit advies in de opmerkingen.
Voorbeeldtechniek was van Baron Schwartz, oorspronkelijk gepubliceerd op Nabble, hier geparafraseerd en uitgebreid.
Antwoord 2, autoriteit 48%
NexusRexheeft een verstrekt zeer goede oplossingvoor het verwijderen met join uit dezelfde tabel.
Als je dit doet:
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
)
u krijgt een foutmelding.
Maar als u de voorwaarde in nog een selectie plaatst:
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
)
het zou het juiste doen!!
Uitleg:de query-optimizer doet een afgeleide samenvoegoptimalisatievoor de eerste zoekopdracht (waardoor deze mislukt met de fout), maar de tweede zoekopdracht komt niet in aanmerking voor de afgeleide samenvoegoptimalisatie. Daarom wordt de optimizer gedwongen om eerst de subquery uit te voeren.
Antwoord 3, autoriteit 14%
De inner join
in uw subquery is niet nodig. Het lijkt erop dat je de items in story_category
wilt verwijderen waar de category_id
niet in de category
-tabel staat.
Doe dit:
DELETE FROM story_category
WHERE category_id NOT IN (
SELECT DISTINCT category.id
FROM category);
In plaats daarvan:
DELETE FROM story_category
WHERE category_id NOT IN (
SELECT DISTINCT category.id
FROM category INNER JOIN
story_category ON category_id=category.id);
Antwoord 4, autoriteit 13%
Onlangs moest ik records bijwerken in dezelfde tabel die ik deed zoals hieronder:
UPDATE skills AS s, (SELECT id FROM skills WHERE type = 'Programming') AS p
SET s.type = 'Development'
WHERE s.id = p.id;
Antwoord 5, autoriteit 7%
Als je niet kunt doen
UPDATE table SET a=value WHERE x IN
(SELECT x FROM table WHERE condition);
omdat het dezelfde tafel is, kun je trick and do doen:
UPDATE table SET a=value WHERE x IN
(SELECT * FROM (SELECT x FROM table WHERE condition) as t)
[bijwerken of verwijderen of wat dan ook]
Antwoord 6, autoriteit 5%
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
)
Antwoord 7, autoriteit 2%
Dit is wat ik deed voor het bijwerken van een Prioriteit-kolomwaarde met 1 als het >=1 is in een tabel en in de WHERE-clausule met behulp van een subquery op dezelfde tabel om ervoor te zorgen dat ten minste één rij Priority=1 ( omdat dat de voorwaarde was die moest worden gecontroleerd tijdens het uitvoeren van de update) :
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);
Ik weet dat het een beetje lelijk is, maar het werkt prima.
Antwoord 8
Voor de specifieke zoekopdracht die het OP probeert te bereiken, is de ideale en meest efficiënte manier om dit te doen, helemaal GEEN subquery te gebruiken.
Hier zijn de LEFT JOIN
-versies van de twee zoekopdrachten van de OP:
SELECT s.*
FROM story_category s
LEFT JOIN category c
ON c.id=s.category_id
WHERE c.id IS NULL;
Opmerking: DELETE s
beperkt verwijderbewerkingen tot de tabel story_category
.
Documentatie
DELETE s
FROM story_category s
LEFT JOIN category c
ON c.id=s.category_id
WHERE c.id IS NULL;
Antwoord 9
De eenvoudigste manier om dit te doen, is door een tabelalias te gebruiken wanneer u verwijst naar de bovenliggende querytabel in de subquery.
Voorbeeld:
insert into xxx_tab (trans_id) values ((select max(trans_id)+1 from xxx_tab));
Wijzig het in:
insert into xxx_tab (trans_id) values ((select max(P.trans_id)+1 from xxx_tab P));
Antwoord 10
U kunt de ID’s van de gewenste rijen in een tijdelijke tabel invoegen en vervolgens alle rijen in die tabel verwijderen.
en dat is misschien wat @Cheekysoft bedoelde door het in twee stappen te doen.
Antwoord 11
Volgens de Mysql UPDATE-syntaxisgekoppeld door @CheekySoft , staat helemaal onderaan.
Momenteel kunt u een tabel niet bijwerken en selecteren uit dezelfde tabel in een subquery.
Ik neem aan dat je uit store_category verwijdert terwijl je er nog steeds uit selecteert in de unie.
Antwoord 12
Als iets niet werkt, wanneer u door de voorkant komt, neem dan de achterdeur:
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;
Het is snel. Hoe groter de gegevens, hoe beter.
Antwoord 13
Probeer resultaat op te slaan van SELECT-instructie in afzonderlijke variabele en gebruik dan dat voor het verwijderen van query.
Antwoord 14
Probeer dit
DELETE FROM story_category
WHERE category_id NOT IN (
SELECT DISTINCT category.id
FROM (SELECT * FROM STORY_CATEGORY) sc;
Antwoord 15
Wat dacht u van deze query hoop dat het
helpt
DELETE FROM story_category LEFT JOIN (SELECT category.id FROM category) cat ON story_category.id = cat.id WHERE cat.id IS NULL
Antwoord 16
Wat betreft, wil u rijen verwijderen in story_category
die niet bestaan in category
.
Hier is uw originele query om de rijen te identificeren om te verwijderen:
SELECT *
FROM story_category
WHERE category_id NOT IN (
SELECT DISTINCT category.id
FROM category INNER JOIN
story_category ON category_id=category.id
);
Het combineren van NOT IN
met een subquery die JOIN
is de oorspronkelijke tabel lijkt unecessarily ingewikkeld. Dit kan worden uitgedrukt in een rechttoe rechtaan manier met not exists
en een gecorreleerde subquery:
select sc.*
from story_category sc
where not exists (select 1 from category c where c.id = sc.category_id);
Nu is het gemakkelijk om dit te wenden tot een delete
statement:
delete from story_category
where not exists (select 1 from category c where c.id = story_category.category_id);
Dit quer zou draaien op elke MySQL-versie, evenals in de meeste andere databases die ik ken.
-- 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;
| Categorie_ID | | -----------: | | 4 | | 5 |