2009-01-08 7 views
1

J'ai une requête comme ceci:PostgreSQL - Échec de la sous-requête corrélée?

SELECT t1.id, 
    (SELECT COUNT(t2.id) 
    FROM t2 
    WHERE t2.id = t1.id 
     ) as num_things 
FROM t1 
WHERE num_things = 5; 

Le but est d'obtenir l'ID de tous les éléments qui apparaissent 5 fois dans l'autre table. Cependant, je reçois cette erreur:

ERROR: column "num_things" does not exist 
SQL state: 42703 

que je fais sans doute quelque chose de stupide ici, comme je suis un peu nouveau pour les bases de données. Est-il possible de résoudre cette requête afin que je puisse accéder à num_things? Ou, sinon, y a-t-il un autre moyen d'atteindre ce résultat?

Répondre

1

Je pense que vous pouvez simplement réécrire votre requête comme ceci:

SELECT t1.id 
FROM t1 
WHERE (SELECT COUNT(t2.id) 
    FROM t2 
    WHERE t2.id = t1.id 
     ) = 5; 
+0

Oh, j'aurais dû relire le but. Tu as raison. Au début, j'étais comme, "mais alors vous perdez les informations de compte, et si vous en avez besoin?" – Kev

+0

oui, cela fonctionne. étrange, je pensais que j'ai essayé cela au début, mais a obtenu un «pas d'agrégats autorisés dans where clause» ou quelque chose. J'ai dû faire quelque chose de différent. Y at-il une raison pour laquelle la façon dont j'ai posté ne fonctionne pas, cependant? – Claudiu

+0

Je ne peux pas le trouver, mais il y avait un fil dans les newsgroups à ce sujet, et il y avait une raison. Tout ce dont je me souviens, c'est que quelqu'un a dit que (si vous avez répété la fonction), dans la plupart des cas, le temps de calcul deux fois est vraiment minime. – Kev

10

Quelques points importants sur l'utilisation de SQL:

  • Vous ne pouvez pas utiliser les alias de colonne dans la clause WHERE, mais vous pouvez en la clause HAVING. C'est la cause de l'erreur que tu as eue.
  • Vous pouvez mieux faire votre compte en utilisant JOIN et GROUP BY qu'en utilisant des sous-requêtes corrélées. Ce sera beaucoup plus rapide.
  • Utilisez la clause HAVING pour filtrer les groupes.

est ici la façon dont j'écris cette requête:

SELECT t1.id, COUNT(t2.id) AS num_things 
FROM t1 JOIN t2 USING (id) 
GROUP BY t1.id 
HAVING num_things = 5; 

Je réalise cette requête peut ignorer l'JOIN avec t1, ​​comme dans la solution de Charles Bretana. Mais je suppose que vous pourriez vouloir que la requête inclue d'autres colonnes de t1.


Re: la question dans le commentaire:

La différence est que la clause WHERE est évaluée sur des rangées, avant GROUP BY réduit les groupes à une seule rangée par groupe. La clause HAVING est évaluée après la formation des groupes. Vous ne pouvez donc pas, par exemple, modifier le COUNT() d'un groupe en utilisant HAVING; vous ne pouvez exclure que le groupe lui-même.

SELECT t1.id, COUNT(t2.id) as num 
FROM t1 JOIN t2 USING (id) 
WHERE t2.attribute = <value> 
GROUP BY t1.id 
HAVING num > 5; 

Dans la demande de recherche ci-dessus, WHERE filtres pour les lignes correspondant à une condition, et HAVING filtres pour les groupes qui ont au moins cinq comptage.

Le point qui provoque la plupart des gens est la confusion quand ils n'ont pas une clause GROUP BY, il semble comme HAVING et WHERE sont interchangeables.

WHERE est évalué avant les expressions dans la liste de sélection. Cela peut ne pas être évident car la syntaxe SQL place la liste de sélection en premier. Vous pouvez donc économiser beaucoup de calculs coûteux en utilisant WHERE pour restreindre les lignes.

SELECT <expensive expressions> 
FROM t1 
HAVING primaryKey = 1234; 

Si vous utilisez une requête comme celle-ci, les expressions dans la liste de sélection sont calculés pour chaque ligne , pour jeter la plupart des résultats en raison de la condition HAVING.Toutefois, la requête ci-dessous calcule l'expression uniquement pour la ligne correspondant à la condition WHERE.

SELECT <expensive expressions> 
FROM t1 
WHERE primaryKey = 1234; 

Donc, pour résumer, les requêtes sont dirigées par le moteur de base de données selon la série d'étapes:

  1. Générer ensemble de lignes de la table (s), y compris toutes les lignes produites par JOIN.
  2. Évaluez les conditions WHERE par rapport à l'ensemble des lignes, en filtrant les lignes qui ne correspondent pas.
  3. Calculer des expressions dans select-list pour chacune des lignes.
  4. Appliquez des alias de colonne (notez qu'il s'agit d'une étape distincte, ce qui signifie que vous ne pouvez pas utiliser d'alias dans les expressions de la liste de sélection).
  5. Condenser les groupes à une seule ligne par groupe, selon la clause GROUP BY.
  6. Évaluez les conditions HAVING par rapport aux groupes, en filtrant les groupes qui ne correspondent pas.
  7. Trier le résultat, conformément à la clause ORDER BY.
+0

Quelle est la différence entre une clause HAVING et une clause WHERE? sémantiquement, en anglais, ils semblent signifier la même chose – Claudiu

+0

Je pensais avoir été seulement pour les agrégats. Bonne réponse, ça a vraiment éclairci mon manque de connaissance. – Keyo

3

Toutes les autres suggestions travailleraient, mais pour répondre à votre question de base, il suffirait d'écrire

SELECT id From T2 
    Group By Id 
    Having Count(*) = 5 
+0

Requête très compacte je l'aime. –

+1

Oui, étant donné le problème exact décrit par l'OP. Mais peut-être avez-vous besoin d'autres colonnes de la table t1. –

+0

Si d'autres colonnes sont nécessaires, cela peut toujours être utilisé comme sous-requête pour limiter la sortie de la table avec d'autres colonnes. –

0

essayer

SELECT t1.id, 
    (SELECT COUNT(t2.id) as myCount 
    FROM t2 
    WHERE t2.id = t1.id and myCount=5 
     ) as num_things 
FROM t1 
+1

Ceci est faux; vous ne pouvez pas utiliser un alias de colonne dans une clause WHERE. –

3

Je voudrais mentionner que, dans PostgreSQL il n'y a aucun moyen d'utiliser une colonne aliasée dans having clause.

à-dire

SELECT USR_ID AS my_id à partir de my_id utilisateur ayant 1 =

de ne fonctionnera pas.

Un autre exemple qui ne va pas travailler:

SELECT su.usr_id AS mon_id, COUNT (*) AS Val de sys_user AS su GROUP BY su.usr_id AYANT val> = 1

Il y aura soit la même erreur: la colonne val n'est pas connue.

Im highliting parce que le projet de loi Karwin a écrit quelque chose pas vraiment vrai pour Postgres.

« Vous ne pouvez pas utiliser des alias de colonne dans la clause WHERE, mais vous pouvez dans la clause HAVING est la cause de l'erreur que vous avez. "