J'ai une table story_category
dans ma base de données 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 exécutant:
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 la table cible 'story_category' pour la mise à jour dans la clause FROM
Comment puis-je surmonter cela?
mysql
subquery
sql-delete
mysql-error-1093
Sergio del Amo
la source
la source
Réponses:
Mise à jour: cette réponse couvre la classification générale des erreurs. Pour une réponse plus spécifique 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 vous utilisez dans la partie SELECT.
Ce comportement est documenté à: 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 remodeler la requête, perdez la sous-requête et joignez la table à elle-même, en utilisant des critères de sélection appropriés. Cela amènera MySQL à voir la table comme deux choses différentes, permettant aux changements destructifs d'aller de l'avant.
Vous pouvez également essayer d'imbriquer 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 elle est moche pour plusieurs raisons, notamment les performances:
La sous-requête imbriquée dans la clause FROM crée une table temporaire implicite , donc elle ne compte pas comme la même table que vous mettez à jour.
... mais attention à l'optimiseur de requêtes
Cependant, sachez qu'à partir de MySQL 5.7.6 et versions ultérieures, l'optimiseur peut optimiser la sous-requête et toujours vous donner l'erreur. Heureusement, la
optimizer_switch
variable peut être utilisée pour désactiver ce comportement; bien que je ne puisse pas recommander de faire cela comme quelque chose de plus qu'une solution à court terme ou pour de petites tâches ponctuelles.Merci à Peter V. Mørch pour ce conseil dans les commentaires.
L'exemple de technique provenait du baron Schwartz, initialement publié chez Nabble , paraphrasé et développé ici.
la source
SET optimizer_switch = 'derived_merge=off';
:-(NexusRex a fourni une très bonne solution pour la suppression avec jointure de la même table.
Si tu fais ça:
vous allez obtenir une erreur.
Mais si vous enveloppez la condition dans une autre sélection:
ça ferait la bonne chose !!
Explication: L'optimiseur de requêtes 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 admissible à l' optimisation de fusion dérivée . Par conséquent, l'optimiseur est obligé d'exécuter la sous-requête en premier.
la source
Le
inner join
dans votre sous-requête n'est pas nécessaire. Il semble que vous souhaitiez supprimer les entréesstory_category
là où lecategory_id
n'est pas dans lecategory
tableau.Faites ceci:
Au lieu de:
la source
DISTINCT
c'est inutile ici - pour une meilleure performance;).where in
le faites pas dans la colonne ID, vous n'avez donc pas besoin de sous-interroger la table principale.Récemment, j'ai dû mettre à jour des enregistrements dans le même tableau que je l'ai fait ci-dessous:
la source
UPDATE skills SET type='Development' WHERE type='Programming';
? Cela ne semble pas répondre à la question d'origine.UPDATE skills SET type='Development' WHERE type='Programming';
. Je ne comprends pas pourquoi tant de gens ne pensent pas à ce qu'ils font ...la source
UPDATE tbl AS a INNER JOIN tbl AS b ON .... SET a.col = b.col
- cela fonctionnerait comme un alias différent pour la même table est utilisée ici. De même, dans la réponse de @ NexusRex, la premièreSELECT
requête agit comme une table dérivée dans laquellestory_category
est utilisée pour la deuxième fois. Donc, l'erreur mentionnée dans le PO ne devrait pas se produire ici, non?Si tu ne peux pas faire
parce que c'est la même table, vous pouvez tromper et faire:
[mettre à jour ou supprimer ou autre]
la source
C'est ce que j'ai fait pour mettre à jour une valeur de colonne Priority de 1 si elle est> = 1 dans une table et dans sa clause WHERE en utilisant une sous-requête sur la même table pour vous assurer qu'au moins une ligne contient Priority = 1 (car c'était le condition à vérifier lors de la mise à jour):
Je sais que c'est un peu moche mais ça marche bien.
la source
La façon la plus simple de procéder consiste à utiliser un alias de table lorsque vous faites référence à une table de requête parent dans la sous-requête.
Exemple :
Changez-le en:
la source
Vous pouvez insérer les identifiants des lignes souhaitées dans une table temporaire, puis supprimer toutes les lignes trouvées dans cette table.
ce qui peut être ce que @Cheekysoft voulait dire en le faisant en deux étapes.
la source
Selon la syntaxe de mise à jour Mysql liée par @CheekySoft, il est indiqué tout en bas.
Je suppose que vous supprimez de store_category tout en le sélectionnant dans l'union.
la source
Pour la requête spécifique que l'OP tente de réaliser, le moyen idéal et le plus efficace de le faire est de ne PAS utiliser de sous-requête.
Voici les
LEFT JOIN
versions des deux requêtes de l'OP:Remarque:
DELETE s
limite les opérations de suppression à lastory_category
table.Documentation
la source
UPDATE
instructions et les sous-requêtes jointes. Vous permettant d'effectuerLEFT JOIN ( SELECT ... )
plutôt que deWHERE IN( SELECT ... )
rendre l'implémentation utile dans de nombreux cas d'utilisation.Si quelque chose ne fonctionne pas, en passant par la porte d'entrée, prenez la porte arrière:
C'est rapide. Plus les données sont volumineuses, mieux c'est.
la source
Essayez d'enregistrer le résultat de l'instruction Select dans une variable distincte, puis utilisez-le pour supprimer la requête.
la source
essaye ça
la source
que diriez-vous de cette requête j'espère que cela aide
la source
DELETE story_category FROM ...
cependant, la sous-requête jointe n'est pas nécessaire dans ce contexte et peut être effectuée à l'aide deLEFT JOIN category AS cat ON cat.id = story_category.category_id WHERE cat.id IS NULL
, Notez que les critères de jointure dans la réponse font référence de manière incorrectestory_category.id = cat.id
En ce qui concerne les préoccupations, vous souhaitez supprimer les lignes
story_category
qui n'existent pas danscategory
.Voici votre requête d'origine pour identifier les lignes à supprimer:
La combinaison
NOT IN
avec une sous-requête quiJOIN
est la table d'origine semble inutilement alambiquée. Cela peut être exprimé de manière plus directe avecnot exists
et une sous-requête corrélée:Maintenant, il est facile de transformer cela en une
delete
déclaration:Cette requête s'exécuterait sur n'importe quelle version de MySQL, ainsi que dans la plupart des autres bases de données que je connais.
Démo sur DB Fiddle :
la source