mysql supprimer en mode sans échec

87

J'ai un instructeur de table et je veux supprimer les enregistrements qui ont un salaire dans une fourchette Une manière intuitive est comme ceci:

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

J'écris donc 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. que signifie vraiment ce message d'erreur et pourquoi mon code est erroné?
  2. comment réécrire ce code pour le faire fonctionner en mode sans échec?

Merci!

roland luo
la source
vouliez-vous garder le mode sans échec activé? et utilisez-vous mySql workbench?
wribit le
la réponse à vos deux questions est oui. Et je suis surpris que lorsque j'ai utilisé jdbc pour supprimer des enregistrements dans des bases de données mysql sans PK, cela ne produise pas d'erreur. Donc, le mode sans échec est uniquement pour mysql workbench?
roland luo
1
non - je demandais parce que si vous vouliez le désactiver dans mySQL workbench, j'aurais pu vous dire comment. Personnellement, je travaille avec ça ... devoir avoir une pièce d'identité est une excellente sécurité - mais en matière de développement, j'ai trouvé que c'était
pénible

Réponses:

225

En cherchant sur Google, la réponse la plus 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 fonctionner en mode sans échec. Pourtant, je ne suis pas tout à fait à l'aise avec cette réponse car elle suppose simplement que vous devriez changer 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 rencontre un autre problème: MySQL applique quelques restrictions aux sous-requêtes, et l'une d'elles 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 sélectionner à partir de la même table dans une sous-requête. Par exemple, cette limitation s'applique aux instructions des 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 dans la clause FROM est stocké en tant que table temporaire, de sorte que les lignes pertinentes de t ont déjà été sélectionnées au moment où la mise à jour vers t a lieu.

Ce dernier élément est votre réponse. Sélectionnez les ID cibles dans une table temporaire, puis supprimez 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 .

rutter
la source
6
Merci pour votre explication! Cependant, j'ai essayé votre code dans mysql workbench et il disait toujours "Vous utilisez le mode de mise à jour sans échec et vous avez essayé de mettre à jour une table sans un WHERE qui utilise une colonne KEY".
roland luo
C'est inattendu. Votre clé primaire est-elle sous un nom différent? Je remarque que votre question semble indiquer qu'elle est nommée ID, alors que ma réponse utilise id.
rutter
Oui, je le change en ID et cela ne fonctionne pas. J'ai essayé de supprimer de l'instructeur où ID = '1' et cela fonctionne donc l'ID est la clé primaire
roland luo
1
@rolandluo Je sais que cela fait longtemps, mais je suis curieux de savoir si vous avez déjà trouvé une solution de contournement. Il est clair que cette méthode a fonctionné dans d’autres circonstances, alors je me demande pourquoi votre cas est différent. Quelque chose de spécifique à votre serveur ou à votre version, peut-être?
rutter
19

Vous pouvez faire croire à MySQL que vous spécifiez en fait 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 effectuer les opérations suivantes:

DELETE FROM tbl WHERE id <> 0
Hugo Zink
la source
12

Désactiver le mode sans échec dans Mysql Workbench 6.3.4.0

Menu Edition => Préférences => Editeur SQL: Autre section: cliquez sur "Mises à jour sécurisées" ... pour décocher l'option

Préférences de Workbench

Peter B
la source
2
"comment réécrire ce code pour le faire fonctionner en mode sans échec ?" ==> Votre réponse indique comment désactiver le mode sans échec;)
ByteHamster
2
Désolé, j'ai totalement mal compris la question. J'ai trouvé ce sujet lorsque je ne pouvais pas supprimer des tables avec Mysql workbench, et il y avait une question similaire dans un commentaire avec mysql workbench, mais je ne peux pas créer de commentaires. Je pensais que ce serait un bon endroit pour écrire ceci ici pour référence future ...
Peter B
0

J'ai une solution beaucoup plus simple, elle fonctionne pour moi; c'est également une solution de contournement, mais peut être utilisable et vous n'avez 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 MaTable O MyField EST_NOT_EQUAL AnyValueNoItemOnMyFieldWillEverHave

Je n'aime pas trop cette solution non plus, c'est pourquoi je suis ici, mais ça marche et ça semble mieux que ce qu'on lui a répondu

Joaq
la source