Erreur MySQL 1093 - ne Pouvez pas spécifier la table cible pour la mise à jour dans la clause from

StackOverflow https://stackoverflow.com/questions/45494

Question

J'ai une table story_category dans ma base de données avec des entrées endommagées.La requête suivante retourne le corrompu les entrées:

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 de l'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 j'obtiens l'erreur suivante:

#1093 - Vous ne pouvez pas spécifier une table cible 'story_category" pour la mise à jour dans la clause from

Comment puis-je surmonter cela?

Était-ce utile?

La solution

Mise à jour:Cette réponse couvre l'erreur générale de classification.Pour une réponse précise sur la façon de mieux gérer les OP exact de requête, veuillez voir les autres réponses à cette question

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

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

Si la logique est assez simple à ré-forme de la requête, perdre de la sous-requête et de rejoindre la table pour lui-même, en employant des critères de sélection retenus.Ce sera la cause de MySQL pour voir la table comme deux choses différentes, permettant destructrice des changements d'aller de l'avant.

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

Sinon, essayez de nidification de la sous-requête plus profondément dans une clause from ...

Si vous avez absolument besoin de la sous-requête, il existe 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);

Le imbriquée sous-requête dans la clause from crée un implicite temporaire table, donc ça ne compte pas comme la même table que vous utilisez la mise à jour.

...mais attention à l'utilisation de l'optimiseur de requête

Cependant, méfiez-vous qu'à partir de MySQL 5.7.6 et là, l'optimiseur peut optimiser la sous-requête, et vous donnons toujours l'erreur.Heureusement, l' optimizer_switch la variable peut être utilisée pour désactiver ce comportement;bien que je ne recommande pas de faire cela comme rien de plus qu'une solution rapide à court terme, ou pour des petites tâches.

SET optimizer_switch = 'derived_merge=off';

Grâce à Peter V.Mørch pour cet avis dans les commentaires.

Exemple a été la technique de Baron Schwartz, publié à l'origine sur Nabble, reformule et prolongée ici.

Autres conseils

NexusRex fourni une très bonne solution pour la suppression avec joindre à partir de la même table.

Si vous faites cela:

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 enroulez la condition dans un select:

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
)

il permettrait de faire la bonne chose!!

Explication: L'optimiseur de requête ne un dérivé de fusion et d'optimisation pour la première requête (ce qui le fait échouer avec le message d'erreur), mais la deuxième requête n'est pas admissible à l' dérivé de fusion et d'optimisation.D'où l'optimiseur est contraint à exécuter la première sous-requête.

L' inner join dans votre sous-requête est inutile.Il semble que vous voulez supprimer les entrées dans story_category où l' category_id n'est pas dans le category table.

Faire cela:

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

Au lieu de cela:

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 eu à mettre à jour des enregistrements dans le même tableau, 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 vous ne pouvez 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 vous tromper et de faire :

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

[mise à jour ou de les supprimer ou quelle que soit]

C'est ce que j'ai fait pour la mise à jour d'une colonne de Priorité de la valeur de 1 si il est >=1 dans une table et dans sa clause where en utilisant une sous-requête sur la même table pour s'assurer qu'au moins une ligne contient Priorité=1 (parce que c'était la condition à vérifier lors de l'exécution 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 laid, mais il ne fonctionne bien.

Vous pouvez insérer la ligne concernée' id dans une table temporaire, puis supprimer toutes les lignes qui se trouvent dans la table.

qui peut être ce que @Cheekysoft entend par le faire en deux étapes.

Selon la mise à JOUR de Mysql Syntaxe lié par @CheekySoft, elle le dit à droite au fond.

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

Je suppose que vous souhaitez supprimer de store_category tout encore en sélectionnant d'elle dans l'union.

Si quelque chose ne fonctionne pas, lors de l'entrée par la porte avant, puis 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, mieux c'est.

Le moyen le plus simple pour ce faire est d'utiliser un alias de la table lorsque vous parlez parent table de requête à l'intérieur de la sous-requête.

Exemple :

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

Modifier:

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

essayez ceci

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

Essayez d'enregistrer le résultat de l'instruction Select dans la variable distincte et ensuite l'utiliser pour supprimer la requête.

comment au sujet de cette requête, j'espère que ça aide

DELETE FROM story_category LEFT JOIN (SELECT category.id FROM category) cat ON story_category.id = cat.id WHERE cat.id IS NULL
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top