MySQL: nieprawidłowe użycie funkcji grupy

105

Używam MySQL. Oto mój schemat:

Dostawcy ( sid: integer , sname: string, adres string)

Części ( pid: integer , pname: string, color: string)

Katalog ( sid: integer, pid: integer , cost: real)

(klucze główne są pogrubione)

Próbuję napisać zapytanie, aby wybrać wszystkie części, które są wykonane przez co najmniej dwóch dostawców:

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

Po pierwsze, czy w ogóle podchodzę do tego we właściwy sposób?

Po drugie otrzymuję ten błąd:

1111 - Nieprawidłowe użycie funkcji grupy

Co ja robię źle?

Nick Heiner
źródło

Odpowiedzi:

176

Trzeba użyć HAVING, nie WHERE.

Różnica jest taka: WHEREklauzula filtruje, które wiersze wybiera MySQL. Następnie MySQL grupuje wiersze i agreguje liczby dla Twojej COUNTfunkcji.

HAVINGjest podobny WHERE, tylko to się dzieje poCOUNT wartość została obliczona, więc to będzie działać zgodnie z oczekiwaniami. Przepisz swoje podzapytanie jako:

(                  -- 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
źródło
25
Również jeśli używana jest funkcja GROUP BY, HAVING powinno nastąpić po GROUP BY
Viacheslav
1
Ponadto, GROUP BY musi być przed HAVING ... Powinien był przeczytać komentarz Bandolero: D
Andrew,
9

Po pierwsze, błąd, który otrzymujesz, wynika z tego, gdzie używasz COUNTfunkcji - nie możesz użyć funkcji agregującej (lub grupy) w WHEREklauzuli.

Po drugie, zamiast używać podzapytania, po prostu połącz tabelę ze sobą:

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

Co moim zdaniem powinno zwrócić tylko wiersze, w których istnieją co najmniej dwa wiersze z tym samym, pidale są co najmniej 2 sids. Aby upewnić się, że otrzymasz tylko jeden wiersz na każdy pid, zastosowałem klauzulę grupowania.

Mark Elliot
źródło
Czy to możliwe, że nawet nie potrzebuję dołączenia? (zobacz moją zaktualizowaną odpowiedź, w której podałem możliwe rozwiązanie).
Nick Heiner,
@Rosarch, myślę, że będziesz chciał użyć COUNT(DISTINCT sid)w zaktualizowanym zapytaniu.
Mark Elliot,
Nie sidzawsze muszą być różne w każdym razie, bo sidi pidrazem tworzą klucz podstawowy dla Catalog?
Nick Heiner,