94 votes

MySQL DELETE FROM avec une sous-requête comme condition

J'essaie de faire une requête comme celle-ci :

DELETE FROM term_hierarchy AS th
WHERE th.parent = 1015 AND th.tid IN (
    SELECT DISTINCT(th1.tid)
    FROM term_hierarchy AS th1
    INNER JOIN term_hierarchy AS th2 ON (th1.tid = th2.tid AND th2.parent != 1015)
    WHERE th1.parent = 1015
);

Comme vous pouvez probablement le constater, je veux supprimer la relation parentale avec 1015 si le même tid a d'autres parents. Cependant, cela me donne une erreur de syntaxe :

You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'AS th
WHERE th.parent = 1015 AND th.tid IN (
  SELECT DISTINCT(th1.tid)
  FROM ter' at line 1

J'ai vérifié la documentation, et j'ai exécuté la sous-requête par elle-même, et tout semble se vérifier. Quelqu'un peut-il comprendre ce qui ne va pas ?

Mise à jour : Comme répondu ci-dessous, MySQL ne permet pas que la table dont vous supprimez les données soit utilisée dans une sous-requête pour la condition.

3 votes

Attention : Bonne réponse au fond stackoverflow.com/a/4471359/956397 ajoutez simplement l'alias de la table après DELETE t FROM table t ...

304voto

CodeReaper Points 1343

Pour les autres qui trouvent cette question en cherchant à supprimer tout en utilisant une sous-requête, je vous laisse cet exemple pour être plus malin que MySQL (même si certaines personnes semblent penser que c'est impossible) :

DELETE e.*
FROM tableE e
WHERE id IN (SELECT id
             FROM tableE
             WHERE arg = 1 AND foo = 'bar');

vous donnera une erreur :

ERROR 1093 (HY000): You can't specify target table 'e' for update in FROM clause

Cependant cette requête :

DELETE e.*
FROM tableE e
WHERE id IN (SELECT id
             FROM (SELECT id
                   FROM tableE
                   WHERE arg = 1 AND foo = 'bar') x);

fonctionnera très bien :

Query OK, 1 row affected (3.91 sec)

Enveloppez votre sous-requête dans une sous-requête supplémentaire (ici nommée x) et MySQL fera volontiers ce que vous demandez.

10 votes

Cela a pris du temps mais j'ai réussi à le faire fonctionner. Important : 1) La première table doit être aliasée comme indiqué ici avec "e", 2) le "x" à la fin n'est pas un placeholder, c'est l'alias pour la table temporaire produite par la sous-requête "(SELECT id FROM tableE WHERE arg = 1 AND foo = 'bar')".

3 votes

Pourquoi cela fonctionne-t-il ? Cela change beaucoup de choses pour moi, mais en plus, cela ne devrait pas fonctionner. C'est fait fonctionne, mais ça ne devrait pas.

1 votes

Incroyable. cela fonctionne réellement ! mais vous n'êtes pas obligé d'aliaser la table avec e... vous pouvez utiliser n'importe quel alias que vous voulez.

45voto

James Wiseman Points 18347

L'alias doit être inclus après le DELETE mot-clé :

DELETE th
FROM term_hierarchy AS th
WHERE th.parent = 1015 AND th.tid IN 
(
    SELECT DISTINCT(th1.tid)
    FROM term_hierarchy AS th1
    INNER JOIN term_hierarchy AS th2 ON (th1.tid = th2.tid AND th2.parent != 1015)
    WHERE th1.parent = 1015
);

3 votes

C'est une bonne réponse. Un aliasing correct contribuera grandement à résoudre les problèmes similaires au message original. (comme le mien.)

43voto

ajreal Points 31456

Vous ne pouvez pas spécifier de table cible pour la suppression.

Une solution de contournement

create table term_hierarchy_backup (tid int(10)); <- check data type

insert into term_hierarchy_backup 
SELECT DISTINCT(th1.tid)
FROM term_hierarchy AS th1
INNER JOIN term_hierarchy AS th2 ON (th1.tid = th2.tid AND th2.parent != 1015)
WHERE th1.parent = 1015;

DELETE FROM term_hierarchy AS th
WHERE th.parent = 1015 AND th.tid IN (select tid from term_hierarchy_backup);

0 votes

Nous avons tous deux raison - voir son commentaire à ma réponse ci-dessous. La syntaxe et la logique des alias étaient toutes deux en cause :)

0 votes

Oui, il semble que la suppression via une sous-requête ne soit pas possible actuellement dans MySQL - merci d'y avoir jeté un œil :)

0 votes

Le "DELETE FROM term_hierarchy AS th" de la dernière ligne ne pose-t-il pas le même problème ? J'obtiens une erreur de syntaxe identique à celle du PO.

12voto

JNK Points 32743

Vous devez à nouveau faire référence à l'alias dans la déclaration de suppression, par exemple :

DELETE th FROM term_hierarchy AS th
....

Comme indiqué ici dans la documentation de MySQL.

0 votes

Il ne s'agit pas d'un alias, vérifiez à nouveau l'OP.

0 votes

@ajreal - Je l'ai fait, et veuillez noter que l'erreur commence à la définition de l'alias, et la documentation MySQL indique explicitement que vous devez utiliser l'alias dans l'instruction DELETE ainsi que dans la clause FROM. Merci pour le vote négatif, cependant.

0 votes

Faites simplement ceci delete from your_table as t1 where t1.id in(select t2.id from your_table t2); Qu'avez-vous obtenu ?

7voto

Darren Edwards Points 11

J'ai abordé la question d'une manière légèrement différente et cela a fonctionné pour moi ;

Je devais enlever secure_links de ma table qui faisait référence à la conditions où il n'y avait plus de lignes de condition. Un script de ménage, en fait. Cela m'a donné l'erreur - Vous ne pouvez pas spécifier la table cible pour la suppression.

En cherchant l'inspiration ici, j'ai trouvé la requête ci-dessous et elle fonctionne parfaitement. C'est parce qu'elle crée une table temporaire sl1 qui est utilisé comme référence pour le DELETE.

DELETE FROM `secure_links` WHERE `secure_links`.`link_id` IN 
            (
            SELECT
                `sl1`.`link_id` 
            FROM 
                (
                SELECT 

                    `sl2`.`link_id` 

                FROM 
                    `secure_links` AS `sl2` 
                    LEFT JOIN `conditions` ON `conditions`.`job` = `sl2`.`job` 

                WHERE 

                    `sl2`.`action` = 'something' AND 
                    `conditions`.`ref` IS NULL 
                ) AS `sl1`
            )

Ça marche pour moi.

0 votes

Duplicata de celui de @CodeReaper ci-dessus... bonne décision cependant... ;)

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X