MySQL: utilisation non valide de la fonction de groupe

105

J'utilise MySQL. Voici mon schéma:

Fournisseurs ( sid: entier , sname: chaîne, chaîne d'adresse)

Parts ( pid: integer , pname: string, color: string)

Catalogue ( sid: entier, pid: entier , coût: réel)

(les clés primaires sont en gras)

J'essaie d'écrire une requête pour sélectionner toutes les pièces fabriquées par au moins deux fournisseurs:

-- Find the pids of parts supplied by at least two different suppliers.
SELECT c1.pid                      -- select the pid
FROM Catalog AS c1                 -- from the Catalog table
WHERE c1.pid IN (                  -- where that pid is in the set:
    SELECT c2.pid                  -- of pids
    FROM Catalog AS c2             -- from catalog
    WHERE c2.pid = c1.pid AND COUNT(c2.sid) >= 2 -- where there are at least two corresponding sids
);

Tout d'abord, est-ce que j'agis de la bonne manière?

Deuxièmement, j'obtiens cette erreur:

1111 - Utilisation incorrecte de la fonction de groupe

Qu'est-ce que je fais mal?

Nick Heiner
la source

Réponses:

174

Vous devez utiliser HAVING, non WHERE.

La différence est la suivante: la WHEREclause filtre les lignes sélectionnées par MySQL. Ensuite, MySQL regroupe les lignes et agrège les nombres pour votre COUNTfonction.

HAVINGest comme WHERE, seulement cela se produit après que la COUNTvaleur a été calculée, donc cela fonctionnera comme vous le souhaitez. Réécrivez votre sous-requête comme:

(                  -- where that pid is in the set:
SELECT c2.pid                  -- of pids
FROM Catalog AS c2             -- from catalog
WHERE c2.pid = c1.pid
HAVING COUNT(c2.sid) >= 2)
rjh
la source
25
De plus, si GROUP BY est utilisé, HAVING doit être après GROUP BY
Viacheslav
1
De plus, GROUP BY doit être avant HAVING .... J'aurais dû lire le commentaire de Bandolero: D
Andrew
9

Premièrement, l'erreur que vous obtenez est due à l'endroit où vous utilisez la COUNTfonction - vous ne pouvez pas utiliser une fonction d'agrégation (ou de groupe) dans la WHEREclause.

Deuxièmement, au lieu d'utiliser une sous-requête, joignez simplement la table à elle-même:

SELECT a.pid 
FROM Catalog as a LEFT JOIN Catalog as b USING( pid )
WHERE a.sid != b.sid
GROUP BY a.pid

Ce qui, je crois, ne devrait renvoyer que les lignes où au moins deux lignes existent avec le même pidmais il y a au moins 2 sids. Pour vous assurer de ne récupérer qu'une seule ligne par, pidj'ai appliqué une clause de regroupement.

Mark Elliot
la source
Est-il possible que je n'ai même pas besoin d'une jointure? (voir ma réponse mise à jour, où j'ai fourni une solution possible.)
Nick Heiner
@Rosarch, je pense que vous voudrez l'utiliser COUNT(DISTINCT sid)dans votre requête mise à jour.
Mark Elliot
N'aurait-il pas sidtoujours besoin d'être distinct de toute façon, car sidet pidforment ensemble une clé primaire pour Catalog?
Nick Heiner