[Dúvida SQL] Retornar o valor 0 com comando COUNT

Pessoal, bom dia!

Estou desenvolvendo uma aplicação estatística para analisar respostas de um questionário socieconômico de alunos ingressantes de uma universidade. Preciso fazer consultas do tipo “Quantidade de mulheres entre 17 e 20 anos” (só um exemplo). Estou utilizando o comando COUNT nos SQLs e está tudo funcionando, porém encontrei um pequeno problema: quando não há nenhuma mulher entre 17 e 20 anos, o resultado da consulta não retorna linha nenhuma e eu precisava que retornasse o valor 0. Tentei usar COALESCE(nome_do_campo, 0), porém não funciona. Já pesquisei bastante na net. Alguém poderia me ajudar a resolver isso ou realmente não tem solução via SQL?

Abraços,
Mariana

Que BD usas? Em todos os que trabalhei sempre tenho ideia de devolver 0 quando não há registos.

Um case não resolve o problema?
Um if?
Decode?

Estou usando MySQL e um CASE também não funcionou… já utilzei Firebird e SQL Server e me lembro que isso funcionava nesses BDs. O estranho dessa situação é que nem um NULL é exibido, ou seja, não mostra linha nenhuma no resultado quando não há dados.

Posta o case que você criou.

SELECT A.DESCRICAO, 
CASE WHEN COUNT(AL.ID) > 0 THEN COUNT(AL.ID) ELSE 0 END AS TOTAL 
FROM ALUNOS AL 
    INNER JOIN RESPOSTAS R ON R.ALUNO = AL.ID AND R.PERGUNTA = 5 
    INNER JOIN ALTERNATIVAS A ON R.ALTERNATIVA = A.ID 
WHERE AL.ANO = 2012 
GROUP BY A.LETRA
ORDER BY A.LETRA

já tentou usar IFNULL ao invés do COALESCE?

No Oracle, ao executar a seguinte query, que retornará 0 linhas…

… a saída é o número 0. Não sei bem como deve funcionar isso no MySQL, mas deveria ter o mesmo comportamento, visto que essa é uma cláusula comum a todos os bancos que adotam o padrão ANSI SQL. Não ocorre nenhum erro durante a execução de seu código?

Esse comando eu não conheço, vou dar uma pesquisada e tentar usar

[quote=FabricioPJ]No Oracle, ao executar a seguinte query, que retornará 0 linhas…

… a saída é o número 0. Não sei bem como deve funcionar isso no MySQL, mas deveria ter o mesmo comportamento, visto que essa é uma cláusula comum a todos os bancos que adotam o padrão ANSI SQL. Não ocorre nenhum erro durante a execução de seu código?[/quote]

Então, no Firebird e SQL Server só assim também sairia 0 D:
Não dá nenhum erro, não. Os valores aparecem corretamente para a query que eu postei nos comentários de cima ai, porém a linha que não tem dados não é exibida ao invés de mostrar 0

A sintaxe de utilização dela é igual a do COALESCE, só que é específica do MySQL, se não me engano// Com IFNULL SELECT ProductName,UnitPrice*(UnitsInStock+IFNULL(UnitsOnOrder,0)) FROM Products // Com COALESCE SELECT ProductName,UnitPrice*(UnitsInStock+COALESCE(UnitsOnOrder,0)) FROM Productshttp://www.w3schools.com/sql/sql_isnull.asp

Seria algo assim

SELECT A.DESCRICAO,   
CASE WHEN COUNT(AL.ID) IS NOT NULL THEN COUNT(AL.ID) ELSE 0 END AS TOTAL   
FROM ALUNOS AL   
    INNER JOIN RESPOSTAS R ON R.ALUNO = AL.ID AND R.PERGUNTA = 5   
    INNER JOIN ALTERNATIVAS A ON R.ALTERNATIVA = A.ID   
WHERE AL.ANO = 2012   
GROUP BY A.LETRA  
ORDER BY A.LETRA 

Ou

SELECT A.DESCRICAO,   
IF COUNT(AL.ID) IS NOT NULL THEN COUNT(AL.ID) ELSE 0 END AS TOTAL   
FROM ALUNOS AL   
    INNER JOIN RESPOSTAS R ON R.ALUNO = AL.ID AND R.PERGUNTA = 5   
    INNER JOIN ALTERNATIVAS A ON R.ALTERNATIVA = A.ID   
WHERE AL.ANO = 2012   
GROUP BY A.LETRA  
ORDER BY A.LETRA 

Acho que o seu problema é que você está gerando os totais a partir dos resultados e não a partir de uma lista de referência.

Imagine por exemplo que quero contar o percentual de torcedores de 5 times, e a tabela tenha os seguintes registros:

ID          NOME            TIME
1           ABEL            PALMEIRAS
2           BRUNO         CORINTHIANS
3           CARLOS       SÃO PAULO
4           DANIEL          SANTOS

E espera o seguinte resultado:

TIME                                 QUANTIDADE
PALMEIRAS                       1
CORINTHIANS                   1
SÃO PAULO                      1
SANTOS                           1
JUVENTUS                        0

Baseado na primeira tabela apenas você nunca conseguirá o resultado abaixo, pois ele nem sabe da existência do Juventus pra começar.

O que você precisaria nesse caso é fazer uma LEFT JOIN da tabela de Times com a tabela de Torcedores.

No seu caso, você precisa criar registros de referência para fazer LEFT JOIN com as respostas dadas.

[quote=digaoneves]A sintaxe de utilização dela é igual a do COALESCE, só que é específica do MySQL, se não me engano// Com IFNULL SELECT ProductName,UnitPrice*(UnitsInStock+IFNULL(UnitsOnOrder,0)) FROM Products // Com COALESCE SELECT ProductName,UnitPrice*(UnitsInStock+COALESCE(UnitsOnOrder,0)) FROM Productshttp://www.w3schools.com/sql/sql_isnull.asp[/quote]

A função IFFNULL não foi reconhecida aqui não

[quote=drsmachado]Seria algo assim

SELECT A.DESCRICAO,   
CASE WHEN COUNT(AL.ID) IS NOT NULL THEN COUNT(AL.ID) ELSE 0 END AS TOTAL   
FROM ALUNOS AL   
    INNER JOIN RESPOSTAS R ON R.ALUNO = AL.ID AND R.PERGUNTA = 5   
    INNER JOIN ALTERNATIVAS A ON R.ALTERNATIVA = A.ID   
WHERE AL.ANO = 2012   
GROUP BY A.LETRA  
ORDER BY A.LETRA 

Ou

SELECT A.DESCRICAO, IF COUNT(AL.ID) IS NOT NULL THEN COUNT(AL.ID) ELSE 0 END AS TOTAL FROM ALUNOS AL INNER JOIN RESPOSTAS R ON R.ALUNO = AL.ID AND R.PERGUNTA = 5 INNER JOIN ALTERNATIVAS A ON R.ALTERNATIVA = A.ID WHERE AL.ANO = 2012 GROUP BY A.LETRA ORDER BY A.LETRA [/quote]

O primeiro rodou, porém ainda não funcionou D:
O segundo está dando erro de sintaxe

Veja a dica do abelbueno. Inner joins só consideram os valores que existem nas duas tabelas. Caso queira valores, independente de existirem em A ou B, precisa do left join.

AbelBueno, entendi o que você quis dizer, porém eu tenho uma tabela ALTERNATIVAS que contém as opções “16 anos”, “17 anos”, “18 anos”, etc. Só que nenhum registro da tabela ALUNOS está vinculado à alternativa “16 anos”. Nesse caso ele saberia da existência do “16 anos”, certo? Seria o caso de mudar pra LEFT JOIN então?

É, isso ta bem estranho, a gente até poderia sugerir outras opções de como verificar se o resultado está vindo Null, como:SELECT A.DESCRICAO, CASE WHEN ISNULL(COUNT(AL.ID)) THEN 0 ELSE COUNT(AL.ID) END AS TOTAL FROM ALUNOS AL INNER JOIN RESPOSTAS R ON R.ALUNO = AL.ID AND R.PERGUNTA = 5 INNER JOIN ALTERNATIVAS A ON R.ALTERNATIVA = A.ID WHERE AL.ANO = 2012 GROUP BY A.LETRA ORDER BY A.LETRA Porém aparentemente o problema é que não está retornando nada (o que eu nunca vi acontecer), porque se estivesse vindo nulo, o COALESCE ja resolveria.

Sim!!

Mudei a junção das tabelas para LEFT e deu na mesma, não sei o que fazer mais e é realmente importante que esses zeros apareçam =/

Então, como diria o Jack, vamos por partes. Posta as duas tabelas para vermos.