Erreur MySQL 1093 – Impossible de spécifier la table cible pour la mise à jour dans la clause FROM

J’ai une table story_category dans ma firebase database avec des entrées corrompues. La requête suivante renvoie les entrées corrompues:

 SELECT * FROM story_category WHERE category_id NOT IN ( SELECT DISTINCT category.id FROM category INNER JOIN story_category ON category_id=category.id); 

J’ai essayé de les supprimer en cours d’exécution:

 DELETE FROM story_category WHERE category_id NOT IN ( SELECT DISTINCT category.id FROM category INNER JOIN story_category ON category_id=category.id); 

Mais je reçois la prochaine erreur:

# 1093 – Vous ne pouvez pas spécifier la table cible ‘story_category’ pour la mise à jour dans la clause FROM

Comment puis-je surmonter cela?

Mise à jour: cette réponse couvre la classification d’erreur générale. Pour une réponse plus précise sur la meilleure façon de traiter la requête exacte de l’OP, veuillez consulter les autres réponses à cette question.

Dans MySQL, vous ne pouvez pas modifier la même table que celle utilisée dans la partie SELECT.
Ce comportement est documenté à l’ adresse suivante : http://dev.mysql.com/doc/refman/5.6/en/update.html

Peut-être que vous pouvez simplement joindre la table à elle-même

Si la logique est suffisamment simple pour redéfinir la requête, perdez la sous-requête et joignez la table à elle-même, en utilisant les critères de sélection appropriés. Cela amènera MySQL à voir la table comme deux choses différentes, permettant des modifications destructives.

 UPDATE tbl AS a INNER JOIN tbl AS b ON .... SET a.col = b.col 

Sinon, essayez d’imbriquer la sous-requête plus profondément dans une clause from …

Si vous avez absolument besoin de la sous-requête, il y a une solution de contournement, mais c’est moche pour plusieurs raisons, y compris la performance:

 UPDATE tbl SET col = ( SELECT ... FROM (SELECT.... FROM) AS x); 

La sous-requête nestede dans la clause FROM crée une table temporaire implicite , elle ne compte donc pas comme la même table que celle mise à jour.

… mais attention à l’optimiseur de requêtes

Cependant, méfiez-vous de MySQL 5.7.6 et versions ultérieures, l’optimiseur peut optimiser la sous-requête, tout en vous donnant l’erreur. Heureusement, la variable optimizer_switch peut être utilisée pour désactiver ce comportement. Bien que je ne puisse pas recommander de le faire autrement que comme une solution à court terme ou pour de petites tâches ponctuelles.

 SET optimizer_switch = 'derived_merge=off'; 

Merci à Peter V. Mørch pour ces conseils dans les commentaires.

Exemple de technique de Baron Schwartz, initialement publié à Nabble , paraphrasé et étendu ici.

NexusRex a fourni une très bonne solution pour supprimer avec la jointure de la même table.

Si tu fais ça:

 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 ) 

vous allez obtenir une erreur.

Mais si vous enveloppez la condition dans une autre sélection

 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 ) 

ça ferait la bonne chose !!

Explication: L’optimiseur de requête effectue une optimisation de fusion dérivée pour la première requête (ce qui entraîne son échec avec l’erreur), mais la deuxième requête n’est pas qualifiée pour l’ optimisation de fusion dérivée. Par conséquent, l’optimiseur doit d’abord exécuter la sous-requête.

La inner join de votre sous-requête est inutile. Il semblerait que vous souhaitiez supprimer les entrées de story_category où le story_category category_id ne figure pas dans la table category .

Faites ceci:

 DELETE FROM story_category WHERE category_id NOT IN ( SELECT DISTINCT category.id FROM category); 

Au lieu de:

 DELETE FROM story_category WHERE category_id NOT IN ( SELECT DISTINCT category.id FROM category INNER JOIN story_category ON category_id=category.id); 

Récemment, j’ai dû mettre à jour des enregistrements dans la même table que je l’ai fait comme ci-dessous:

 UPDATE skills AS s, (SELECT id FROM skills WHERE type = 'Programming') AS p SET s.type = 'Development' WHERE s.id = p.id; 
 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 ) 

Si tu ne peux pas faire

 UPDATE table SET a=value WHERE x IN (SELECT x FROM table WHERE condition); 

parce que c’est la même table, vous pouvez tromper et faire:

 UPDATE table SET a=value WHERE x IN (SELECT * FROM (SELECT x FROM table WHERE condition) as t) 

[mettre à jour ou supprimer ou autre]

C’est ce que j’ai fait pour mettre à jour une valeur de colonne Priorité de 1 si elle est> = 1 dans une table et de sa clause WHERE en utilisant une sous-requête sur la même table pour vérifier qu’au moins une ligne contient Priorité = 1 condition à vérifier lors de la mise à jour):

 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); 

Je sais que c’est un peu moche mais ça marche très bien.

Vous pouvez insérer les identifiants de lignes souhaités dans une table temporaire, puis supprimer toutes les lignes de cette table.

C’est peut-être ce que @Cheekysoft a voulu faire en deux étapes.

Selon la syntaxe Mysql UPDATE liée par @CheekySoft, il est indiqué tout en bas.

Actuellement, vous ne pouvez pas mettre à jour une table et la sélectionner dans la même table dans une sous-requête.

Je suppose que vous supprimez de store_category tout en le sélectionnant dans l’union.

Si quelque chose ne fonctionne pas, en passant par la porte d’entrée, prenez la porte arrière:

 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; 

C’est rapide. Plus les données sont grandes, mieux c’est.

Essayez d’enregistrer le résultat de l’instruction Select dans une variable distincte, puis utilisez-la pour la requête de suppression.

que diriez-vous de cette requête espère que cela aide

 DELETE FROM story_category LEFT JOIN (SELECT category.id FROM category) cat ON story_category.id = cat.id WHERE cat.id IS NULL 

La méthode la plus simple consiste à utiliser un alias de table lorsque vous faites référence à une table de requête parent dans la sous-requête.

Exemple :

 insert into xxx_tab (trans_id) values ((select max(trans_id)+1 from xxx_tab)); 

Changez le pour:

 insert into xxx_tab (trans_id) values ((select max(P.trans_id)+1 from xxx_tab P)); 

essaye ça

 DELETE FROM story_category WHERE category_id NOT IN ( SELECT DISTINCT category.id FROM (SELECT * FROM STORY_CATEGORY) sc;