MySQL: uso inválido de função de grupo

104

Estou usando o MySQL. Aqui está meu esquema:

Fornecedores ( sid: inteiro , sname: string, string de endereço)

Partes ( pid: inteiro , pname: string, cor: string)

Catálogo ( sid: inteiro, pid: inteiro , custo: real)

(as chaves primárias estão em negrito)

Estou tentando escrever uma consulta para selecionar todas as peças feitas por pelo menos dois fornecedores:

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

Em primeiro lugar, estou mesmo fazendo isso da maneira certa?

Em segundo lugar, recebo este erro:

1111 - Uso inválido de função de grupo

O que estou fazendo de errado?

Nick Heiner
fonte

Respostas:

173

Você precisa usar HAVING, não WHERE.

A diferença é: a WHEREcláusula filtra quais linhas o MySQL seleciona. Então o MySQL agrupa as linhas e agrega os números para sua COUNTfunção.

HAVINGé como WHERE, só acontece depois que o COUNTvalor foi calculado, então vai funcionar como você espera. Reescreva sua subconsulta como:

(                  -- 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
fonte
25
Além disso, se GROUP BY for usado, HAVING deve ser após GROUP BY
Viacheslav
1
Além disso, GROUP BY precisa ser antes de TER .... Deveria ter lido o comentário de Bandolero: D
Andrew
8

Primeiro, o erro que você está obtendo é devido ao local em que você está usando a COUNTfunção - você não pode usar uma função de agregação (ou grupo) na WHEREcláusula.

Em segundo lugar, em vez de usar uma subconsulta, simplesmente junte a tabela a ela mesma:

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

O que eu acredito que deva retornar apenas linhas onde existem pelo menos duas linhas com o mesmo, pidmas há pelo menos 2 sids. Para ter certeza de que você receberá de volta apenas uma linha, pidapliquei uma cláusula de agrupamento.

Mark Elliot
fonte
É possível que eu nem precise de um cadastro? (veja minha resposta atualizada, onde forneci uma solução possível.)
Nick Heiner
@Rosarch, acho que você vai querer usar COUNT(DISTINCT sid)em sua consulta atualizada.
Mark Elliot
Nem sidsempre teria que ser distinto de qualquer maneira, porque side pidjuntos formam uma chave primária para Catalog?
Nick Heiner