2010-02-25 16 views
70

Sto usando MySQL. Qui è il mio schema:MySQL: uso non valido della funzione di gruppo

Fornitori (sid: interi, sname: stringa, stringa di indirizzo)

Parti (PID: interi, pname: stringa, colore: String)

catalogo (sid: integer, pid: integer, costo: vero e proprio)

(le chiavi primarie sono in grassetto)

sono t rying di scrivere una query per selezionare tutte le parti che sono fatti da almeno due fornitori:

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

Prima di tutto, sono io andando anche su questo il modo giusto?

In secondo luogo, ottengo questo errore:

1111 - Invalid use of group function

Che cosa sto facendo di sbagliato?

risposta

120

È necessario utilizzare HAVING, non DOVE.

La differenza è: la clausola WHERE filtra quali righe MySQL seleziona. Quindi MySQL raggruppa le righe e aggrega i numeri della funzione COUNT.

HAVING è come DOVE, solo succede dopo il valore COUNT è stato calcolato, quindi funzionerà come previsto. Riscrivi la subquery come:

(     -- 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) 
+1

Quindi "HAVING" conta prima i filtri, giusto? –

+15

Anche se si utilizza GROUP BY, HAVING dovrebbe essere dopo GROUP BY – Viacheslav

+0

Inoltre, GROUP BY deve essere prima di HAVING .... Avrebbe dovuto leggere il commento di Bandolero: D – Andrew

4

In primo luogo, l'errore che si ottiene è dovuto a dove si sta utilizzando la funzione COUNT - non è possibile utilizzare una funzione di aggregazione (o gruppo) nella clausola WHERE.

In secondo luogo, invece di utilizzare un subquery, è sufficiente partecipare al tavolo a se stessa:

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

Quale credo dovrebbe restituire solo le righe in cui esistono almeno due righe con lo stesso pid ma c'è sono almeno 2 sid s. Per essere sicuro di tornare indietro di una riga per pid, ho applicato una clausola di raggruppamento.

+0

E 'possibile che non sia nemmeno necessario un join? (vedi la mia risposta aggiornata, dove ho fornito una possibile soluzione.) –

+0

@Rosarch, penso che vorrete usare 'COUNT (DISTINCT sid)' nella vostra query aggiornata. –

+0

Non dovremmo comunque distinguere 'sid', perché' sid' e 'pid' formano insieme una chiave primaria per' Catalog'? –

Problemi correlati