2008-10-09 8 views
3

Je viens d'apprendre (hier) à utiliser "existe" au lieu de "dans".SQL - table alias scope

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

J'ai quelques questions à ce sujet:

1) L'explication que j'ai compris était: « La raison pour laquelle cela vaut mieux parce que seules les valeurs correspondantes seront retournées au lieu de construire un massif liste des résultats possibles ". Cela signifie-t-il que, bien que la première sous-requête puisse renvoyer 900 résultats, la seconde renvoie seulement 1 (oui ou non)?

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

3) Quelle est la portée de l'alias dans la deuxième sous-requête? ... l'alias ne vit-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, si j'utilise le même alias (o pour la table uneautretable) Dans le second « existe » il se présente un problème avec le premier existe? ou sont-ils totalement indépendants?

Est-ce que c'est quelque chose que Oracle est lié ou est-ce valable pour la plupart des SGBDR?

Merci beaucoup

+0

Il est « EXISTE », non "exister". – Constantin

+0

La deuxième requête n'analyse pas. Les textes mentionnent "le second existe" alors voulez-vous dire "ET existe" (pour ET? – philipxy

Répondre

3

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

Dans tous DBMSes j'ai testé, alias est uniquement valable à l'intérieur du()

BTW, vous pouvez réécrire la requête comme:

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
1

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') 
2
  1. Oracle spécifique: Lorsque vous écrivez une requête en utilisant la clause IN, vous indiquez l'optimiseur à base de règles que vous voulez que la requête interne pour conduire la requête externe. Lorsque vous écrivez EXISTS dans une clause where, vous indiquez à l'optimiseur que vous souhaitez que la requête externe soit exécutée en premier, en utilisant chaque valeur pour extraire une valeur de la requête interne. Voir "Difference between IN and EXISTS in subqueries".
  2. Probablement.
  3. L'alias déclaré à l'intérieur de la sous-requête existe à l'intérieur de la sous-requête. En passant, je ne pense pas que votre exemple avec 2 sous-requêtes ANDed est valide SQL. Vouliez-vous dire UNION au lieu de AND?
3

Vous parcourez un territoire compliqué, connu sous le nom de 'sous-requêtes corrélées'.Comme nous n'avons pas d'informations détaillées sur vos tables et les structures clés, certaines des réponses peuvent seulement être «peut-être».

Dans votre requête IN initiale, la notation serait valide si OtherTable contient une colonne NameID (et, en effet, si OtherDesc existe en tant que colonne dans Table ou OtherTable - ce qui n'est pas clair dans aucun de vos exemples, mais est probablement une colonne de OtherTable). Ce comportement est ce qui rend une sous-requête corrélée dans une sous-requête corrélée. C'est aussi une source habituelle d'angoisse pour les gens quand ils tombent dessus pour la première fois - invariablement par accident. Puisque le standard SQL impose le comportement 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 avec le nom pertinent dans les tables mentionnées dans la sous-requête mais qu'il y a une colonne avec nom pertinent dans les tables mentionnées dans la requête externe (principale), aucun produit qui veut réclamer la conformité à (ce peu de) le standard SQL fera n'importe quoi différent. La réponse à votre Q1 est "ça dépend", mais étant donné des hypothèses plausibles (NameID existe comme une colonne dans les deux tables, OtherDesc existe seulement dans OtherTable), les résultats devraient être les mêmes en termes de l'ensemble de données retourné, mais peut ne pas être équivalent en termes de performance.

La réponse à votre Q2 est que dans le passé, vous utilisiez un SGBD inférieur, voire défectueux. S'il supportait EXISTS, alors le SGBD pourrait encore se plaindre de la cardinalité du résultat.

La réponse à votre Q3 telle qu'appliquée à la première requête EXISTS est "t est disponible comme alias dans l'instruction, mais o n'est disponible qu'en tant qu'alias entre parenthèses". Appliqué à votre deuxième boîte d'exemple - avec ET reliant deux sous-sélections (dont la seconde n'a pas la parenthèse ouverte quand je la regarde), alors "t est disponible comme alias dans toute l'instruction et fait référence à la même chose table, mais il existe deux alias différents étiquetés 'o', un pour chaque sous-requête ". Notez que la requête peut renvoyer aucune donnée si OtherDesc est unique pour une valeur NameID donnée dans OtherTable; sinon, il nécessite deux lignes dans OtherTable avec le même NameID et les deux valeurs OtherDesc pour chaque ligne dans Table avec cette valeur NameID.

1

Il est difficile de généraliser que EXISTS est toujours mieux que IN. Logiquement si c'est le cas, alors 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, habituellement c'est un balayage de table complet de la table interne une fois sans enlever les NULLs (donc si vous avez des NULL dans votre table interne, IN ne supprimera pas NULLS par défaut) ... Alors EXISTS supprime NULL et dans le cas de sous-requête corrélée, exécute une requête interne pour chaque ligne de la requête externe.

En supposant qu'il n'y a pas NULLS et que ce soit une requête simple (sans corrélation), EXIST pourrait mieux fonctionner si la ligne que vous trouvez n'est pas la dernière ligne. Si elle se trouve être la dernière ligne, EXISTS peut avoir besoin de scanner jusqu'à la fin comme dans .. si de performances similaires ...

Mais IN et EXISTS ne sont pas interchangeables ...