Question

Je viens d'apprendre (hier) d'utiliser "existe" " au lieu de "dans".

 BAD
 select * from table where nameid in ( 
          select nameid from othertable where otherdesc =  'SomeDesc' )      
 GOOD
 select * from table t where exists ( 
          select nameid from othertable o where t.nameid = o.nameid and otherdesc =  'SomeDesc' )      

Et j'ai quelques questions à ce sujet:

1) Si j'ai bien compris, l'explication était la suivante: "Cela est préférable, car seules les valeurs correspondantes sont renvoyées au lieu de créer une liste exhaustive de résultats possibles" . Cela signifie-t-il que bien que la première sous-requête puisse renvoyer 900 résultats, la seconde n'en renvoie que 1 (oui ou non)?

2) Auparavant, le SGBDR se plaignait: "seules les 1000 premières lignes pourraient être récupérées", cette seconde approche résoudrait ce problème?

3) Quelle est la portée de l'alias de la deuxième sous-requête? ... l'alias ne réside-t-il que dans la parenthèse?

par exemple

 select * from table t where exists ( 
          select nameid from othertable o where t.nameid = o.nameid and otherdesc =  'SomeDesc' )      
 AND 
          select nameid from othertable o where t.nameid = o.nameid and otherdesc =  'SomeOtherDesc' )      

C’est-à-dire si j’utilise le même alias (o pour la table othertable) dans le second "exist". présentera-t-il un problème avec le premier existe? ou sont-ils totalement indépendants?

S'agit-il d'un problème uniquement lié à Oracle ou est-il valable pour la plupart des SGBDR?

Merci beaucoup

Était-ce utile?

La solution

Il est spécifique à chaque SGBD et dépend de l'optimiseur de requête. Certains optimiseurs détectent la clause IN et la traduisent.

Dans tous les SGBD que j'ai testés, l'alias n'est valide qu'à l'intérieur du ()

BTW, vous pouvez réécrire la requête en tant que:

select t.* 
from table t 
join othertable o on t.nameid = o.nameid 
    and o.otherdesc in ('SomeDesc','SomeOtherDesc');

Et pour répondre à vos questions:

  1. oui
  2. oui
  3. oui

Autres conseils

Vous entrez dans un territoire complexe, appelé "sous-requêtes corrélées". Dans la mesure où nous ne disposons pas d'informations détaillées sur vos tables et les structures de clés, certaines réponses ne peuvent être que "peut-être".

Dans votre requête IN initiale, la notation serait valide, que OtherTable contienne ou non une colonne NameID (et, en fait, si OtherDesc existe en tant que colonne dans Table ou OtherTable - ce qui n’est clair dans aucun de vos exemples, mais vraisemblablement est une colonne de OtherTable). C'est ce comportement qui transforme une sous-requête corrélée en une sous-requête corrélée. C'est aussi une source d'angoisse de routine pour les gens lorsqu'ils le rencontrent pour la première fois - invariablement par accident. Comme la norme SQL impose d'interpréter un nom dans la sous-requête comme faisant référence à une colonne dans la requête externe, s'il n'y a pas de colonne portant le nom correspondant dans les tables mentionnées dans la sous-requête, mais s'il existe une colonne contenant le nom correspondant. nom pertinent dans les tables mentionnées dans la requête (principale) extérieure, aucun produit qui souhaite revendiquer la conformité à (ce bit de) la norme SQL ne fera autre chose.

La réponse à votre question Q1 est "Cela dépend", mais étant donné les hypothèses plausibles (NameID existe en tant que colonne dans les deux tables; OtherDesc n'existe que dans OtherTable), les résultats doivent être identiques en termes de jeu de données renvoyé, mais peut ne pas être équivalent en termes de performances.

La réponse à votre Q2 est que, dans le passé, vous utilisiez un SGBD inférieur, voire défectueux. S'il prend en charge EXISTS, le SGBD peut toujours se plaindre de la cardinalité du résultat.

La réponse à votre Q3, telle qu’elle est appliquée à la première requête EXISTS, est la suivante: "t est disponible sous forme d’alias dans l’instruction, mais o n’est disponible que sous forme d’alias à l’intérieur des parenthèses". Comme appliqué à votre deuxième exemple - avec AND connectant deux sous-sélections (la deuxième entre lesquelles manque la parenthèse ouverte lorsque je la regarde), puis "t est disponible comme alias dans l’énoncé et fait référence à la même table, mais il existe deux alias différents étiquetés «o», un pour chaque sous-requête "." Notez que la requête peut ne renvoyer aucune donnée si OtherDesc est unique pour une valeur NameID donnée dans OtherTable; sinon, il faut deux lignes dans OtherTable avec le même NameID et les deux valeurs OtherDesc pour chaque ligne de la table avec cette valeur NameID.

  1. Spécifique à Oracle: lorsque vous écrivez une requête à l'aide de la clause IN, vous indiquez à l'optimiseur à base de règles que vous souhaitez que la requête interne pilote la requête externe. Lorsque vous écrivez EXISTS dans une clause where, vous indiquez à l'optimiseur que vous souhaitez exécuter la requête externe en premier, en utilisant chaque valeur pour extraire une valeur de la requête interne. Voir " Différence entre IN et EXISTS dans les sous-requêtes " .
  2. Probablement.
  3. Un alias déclaré dans une sous-requête vit dans une sous-requête. En passant, je ne pense pas que votre exemple avec 2 sous-requêtes ANDed soit valide SQL. Voulez-vous dire UNION au lieu de AND?

Personnellement, j'utiliserais une jointure plutôt qu'une sous-requête pour cela.

SELECT t.*
FROM yourTable t
    INNER JOIN otherTable ot
        ON (t.nameid = ot.nameid AND ot.otherdesc = 'SomeDesc')

Il est difficile de généraliser le fait qu'EXISTS est toujours meilleur que IN. Logiquement, si tel est le cas, la communauté SQL aurait remplacé IN par EXISTS ... Notez également que IN et EXISTS ne sont pas identiques, les résultats peuvent être différents lorsque vous utilisez les deux ...

Avec IN, il s’agit généralement d’une analyse complète de la table interne une fois sans supprimer les valeurs NULL (ainsi, si vous avez des valeurs NULL dans votre table interne, IN ne supprime pas NULLS par défaut) ... Alors que EXISTS supprime NULL et en cas de sous-requête corrélée, elle exécute une requête interne pour chaque ligne d'une requête externe.

En supposant qu’il n’existe pas de NULLS et qu’il s’agisse d’une requête simple (sans corrélation), EXIST peut fonctionner mieux si la ligne que vous recherchez n’est pas la dernière. S’il s’agit de la dernière ligne, EXISTS devra peut-être numériser jusqu’à la fin comme IN .. des performances similaires ...

Mais IN et EXISTS ne sont pas interchangeables ...

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top