web-dev-qa-db-fra.com

mysql delete en mode sans échec

J'ai un instructeur de table et je veux supprimer les enregistrements qui ont un salaire dans une fourchette. 

delete from instructor where salary between 13000 and 15000;

Cependant, en mode sans échec, je ne peux pas supprimer un enregistrement sans fournir une clé primaire (ID).

Alors j'écris le sql suivant: 

delete from instructor where ID in (select ID from instructor where salary between 13000 and 15000);

Cependant, il y a une erreur:

You can't specify target table 'instructor' for update in FROM clause

Je suis confus parce que quand j'écris

select * from instructor where ID in (select ID from instructor where salary between 13000 and 15000);

cela ne produit pas d'erreur.

Ma question est:

  1. qu'est-ce que ce message d'erreur signifie vraiment et pourquoi mon code est erroné?
  2. comment réécrire ce code pour le faire fonctionner en mode sans échec?

Merci!

69
roland luo

Googling autour, la réponse populaire semble être "il suffit de désactiver le mode sans échec" :

SET SQL_SAFE_UPDATES = 0;
DELETE FROM instructor WHERE salary BETWEEN 13000 AND 15000;
SET SQL_SAFE_UPDATES = 1;

Si je suis honnête, je ne peux pas dire que j'ai déjà pris l'habitude de courir en mode sans échec. Pourtant, je ne suis pas tout à fait à l'aise avec cette réponse, car elle suppose que vous devriez modifier la configuration de votre base de données chaque fois que vous rencontrez un problème.

Ainsi, votre deuxième requête est plus proche de la marque, mais pose un autre problème: MySQL applique quelques restrictions aux sous-requêtes, dont l’une est que vous ne pouvez pas modifier une table en la sélectionnant dans une sous-requête.

Citant le manuel MySQL, Restrictions sur les sous-requêtes :

En général, vous ne pouvez pas modifier une table et effectuer une sélection dans la même table dans une sous-requête. Par exemple, cette limitation s’applique aux instructions de les formes suivantes:

DELETE FROM t WHERE ... (SELECT ... FROM t ...);
UPDATE t ... WHERE col = (SELECT ... FROM t ...);
{INSERT|REPLACE} INTO t (SELECT ... FROM t ...);

Exception: l'interdiction précédente ne s'applique pas si vous utilisez une sous-requête pour la table modifiée dans la clause FROM. Exemple:

UPDATE t ... WHERE col = (SELECT * FROM (SELECT ... FROM t...) AS _t ...);

Ici, le résultat de la sous-requête de la clause FROM est stocké sous forme de table temporaire. Par conséquent, les lignes correspondantes dans t ont déjà été sélectionnées au moment de la mise à jour de t.

Ce dernier bit est votre réponse. Sélectionnez les ID cibles dans une table temporaire, puis supprimez-les en référençant les ID de cette table:

DELETE FROM instructor WHERE id IN (
  SELECT temp.id FROM (
    SELECT id FROM instructor WHERE salary BETWEEN 13000 AND 15000
  ) AS temp
);

Démo SQLFiddle .

178
rutter

Vous pouvez faire croire à MySQL que vous spécifiez une colonne de clé primaire. Cela vous permet de "remplacer" le mode sans échec.

En supposant que vous ayez une table avec une clé primaire numérique à incrémentation automatique, vous pouvez procéder comme suit:

DELETE FROM tbl WHERE id <> 0
12
Hugo Zink

Désactivation du mode sans échec dans Mysql Workbench 6.3.4.0

Menu Edition => Préférences => Éditeur SQL: Autre section: cliquez sur "Mises à jour sûres" ... pour décocher

entrez la description de l'image ici

10
Peter B

J'ai une solution beaucoup plus simple, cela fonctionne pour moi; c’est aussi une solution de contournement mais qui peut être utilisable et vous n’aurez pas à modifier vos paramètres. Je suppose que vous pouvez utiliser une valeur qui ne sera jamais là, puis vous l'utilisez dans votre clause WHERE

SUPPRIMER DE MyTable WHERE MyField IS_NOT_EQUAL AnyValueNoItemOnMyFieldWillEverHave

Je n'aime pas trop cette solution, c'est pourquoi je suis ici, mais cela fonctionne et semble mieux que ce à quoi il a été répondu

0
Joaq

Il semble que votre session MySql possède l’option safe-updates. Cela signifie que vous ne pouvez pas mettre à jour ou supprimer des enregistrements sans spécifier de clé (ex. Clé primaire) dans la clause where.

Essayer

SET SQL_SAFE_UPDATES = 0;

0
yakob abada