it-swarm-fr.com

Problème avec la sous-requête MySQL

Pourquoi cette requête

DELETE FROM test 
WHERE id = ( SELECT id 
             FROM (SELECT * FROM test) temp 
             ORDER BY Rand() 
             LIMIT 1
           );

parfois, supprimez 1 rangée, parfois 2 rangées et parfois rien?

Si je l'écris dans ce formulaire:

SET @var = ( SELECT id 
             FROM (SELECT * FROM test) temp 
             ORDER BY Rand() 
             LIMIT 1
           ); 
DELETE FROM test 
WHERE [email protected];

ensuite, cela fonctionne correctement - est un problème dans la sous-requête?

16
tomas.lang

La raison pour laquelle la première requête ne fonctionne pas toujours sur la manière dont MySQL traite les sous-sols. En fait, (((( Les sous-requêtes subiront des réécrites et des transformations .

Il existe quatre (4) composants expliqués ici:

  • Item_in_optimizer
  • Item_in_subselect
  • Item_ref
  • Gaucher_expression_cache

Dans les exemples postés, il serait impossible de permettre à un élément_ref de devenir une référence d'auto. En termes de requête de suppression unique, la table d'essai dans son ensemble ne peut se référencer entièrement car certaines clés sont disponibles pendant la transformation et certaines ne le sont pas. Par conséquent, lorsqu'une requête effectue une référence d'auto-référence, une clé (dans ce cas ID) peut disparaître dans une transformation même si la table auto-référencée réelle a la clé.

Les sous-requêtes MySQL ne sont que géniales pour les sous-sélectionneurs, même auto-référençant une table plusieurs fois. On ne peut pas indiquer la même chose pour des requêtes non sélectionnées.

J'espère que cette explication aide.

13
RolandoMySQLDBA

Je pense que la raison pour laquelle elle ne fonctionne pas comme prévu n'est pas la manière dont MySQL traite les sous-sols, mais comment MySQL traite UPDATE déclarations. La déclaration:

DELETE 
FROM test 
WHERE id = 
      ( SELECT id 
        FROM 
            ( SELECT * 
              FROM test
            ) temp 
        ORDER BY Rand() 
        LIMIT 1
      ) 

traitera la ligne de condition WHERE par ligne. Signification, pour chaque rangée, il exécutera la sous-requête et testera le résultat contre id:

  ( SELECT id 
    FROM 
        ( SELECT * 
          FROM test
        ) temp 
    ORDER BY Rand() 
    LIMIT 1
  ) 

Donc, cela correspondra occasionnellement à (et supprimera) 0, 1, 2 ou encore plus de lignes!


Vous pouvez le réécrire comme ceci et la sous-requête sera traitée une fois:

DELETE t
FROM 
      test t
  JOIN 
      ( SELECT id 
        FROM test  
        ORDER BY Rand() 
        LIMIT 1
      ) tmp
    ON tmp.id = t.id
7
ypercubeᵀᴹ

De la première balle sur cette page , LIMIT n'est pas pris en charge dans les sous-requêtes MySQL. Je ne sais pas pourquoi cela ne jette pas une erreur pour vous, cependant.

1
Derek Downey