1) É realmente necessário, sempre que usar INNER JOIN
+ GROUP BY
, colocar em todos os campos uma função matemática (como SUM,MAX, MIN, etc)?
Eu tentei rodar o seu código e não funcionou. O problema apareceu justamente no
GROUP BY
nome,
mes_ano -- erro nessa linha
eu vou responder isso na 2), já que esse é o motivo do erro.
Mas quanto à 'necessidade' de usar funções matemáticas com GROUP BY
, não é bem assim que a banda toca.
O GROUP BY
faz com que os dados sejam unificados seguindo tais regras, ou seja, uma linha é reservada para os campos que se conectam:
SELECT A, B, C FROM TABELA
GROUP BY A, B, C
Aqui teremos várias combinações de diferentes As com diferentes Bs com diferentes Cs, mas esse GROUP BY
vai fazer com que todas as linhas que têm combinações A, B, C iguais se transformem em UMA só. Nós então usamos o COUNT() para saber quantas vezes essa mesma combinação foi encontrada, o SUM() para somar todos os valores do campo _ de todas as linhas que apresentaram tal combinação, o MAX() para saber qual foi o maior valor encontrado entre todas essas linhas com essa combinação particular e MIN(_) para o mesmo intuito.
A palavra para isso pode ser unificação, até porque não será raro você usar
SELECT COUNT(*), SUM(QUANTIDADE), MAX(QUANTIDADE), MIN(QUANTIDADE) FROM ITENS_NOTAS_FISCAIS;
em uma querry já que você sabe que ela retorna apenas uma linha.
E é por isso que você não precisa especificar essas funções matemáticas no GROUP BY
você usa essas funções matemáticas porque sabe que a consulta retorna apenas uma linha.
2) Não entendi porque não se pode usar o alias MES_ANO no GROUP BY
, é obrigatório ou apenas uma boa prática?
Alias é nada mais que um apelido, para ele se tornar um 'campo' real, você teria que fazer uma subquerry (subconsulta), farei isso na próxima pergunta.
O que acontece é o seguinte: o GROUP BY
alinha os dados e apresenta fazendo uma agrupação (veja só) entre os dados, esse tipo de agrupação ocorre antes da apresentação de dados, da mesma forma que o WHERE
seleciona o que vai ser apresentado, mas o ORDER BY
já realiza esse processo um pouco depois e por isso:
SELECT * FROM TABELA
WHERE ALIAS_QUALQUER <> 0 --- ERRORRRR!!!!!
GROUP BY ALIAS_QUALQUER --- ERRORRRR! EXQUECE, PAPAI, VOCÊ SeQueLou
ORDER BY ALIAS_QUALQUER --- IRÁ FUNCIONAR NORMALMENTE PORQUE O ORDER BY ACONTECE POR ÚLTIMO
[Copiei de uma resposta do StackOverFlow e traduzi aqui]
FROM
Clause é processada e todas as tabelas requisitadas são identificadas, depois de resolver possíveis definições de views.
WHERE
clause é processada, aplicando condições às linhas da tabela.
GROUP BY
clause é processa, aplicando funções agregadas às linhas remanescentes depois do WHERE
.
HAVING
clause é processada, aplicando condições adicionais após o GROUP BY
.
Apenas agora o SELECT
lista as linhas escolhidas e atribuindo os aliases às linhas.
ORDER BY
clause é processada, mas como ela só acontece após o SELECT
, ela já tem, finalmente, acesso aos aliases atribuídos no seu código.
3) Acabei não usando a subconsulta, isso piora a performance do meu código?
Geralmente, join vai ser mais rápida que uma subquerry. Mas isso não quer dizer que subquerries são inúteis ou inutilizáveis.
Por exemplo, usando o seu próprio código com subquerry, poderíamos resolver o problema de usar aliases no ORDER BY
dessa maneira.
Eu escrevi em ORACLE, então para funcionar no seu caso você precisa comentar o TO_CHAR e descomentar a linha de baixo.
SELECT
X.nome
,X.mes_ano
,X.qtd_total
,X.qtd_limite
FROM
(SELECT
TC.NOME
,TO_CHAR(NF.DATA_VENDA, 'YYYY-MM') AS MES_ANO
--,date_format(nf.data_venda, '%Y-%m')
,SUM(quantidade) AS qtd_total
,volume_de_compra AS qtd_limite
,( CASE WHEN SUM(quantidade) <= volume_de_compra
THEN 'VÁLIDA'
ELSE 'INVÁLIDA'
END) AS STATUS
FROM
tabela_de_clientes tc
INNER JOIN notas_fiscais nf
ON tc.cpf = nf.cpf
INNER JOIN itens_notas_fiscais inf
ON nf.numero = inf.numero
GROUP BY
TC.NOME
,TO_CHAR(NF.DATA_VENDA, 'YYYY-MM')
--,date_format(nf.data_venda, '%Y-%m')
,volume_de_compra
) X
ORDER BY
X.nome
,X.mes_ano
Eu entendo que o código não mudou tanto do seu, e embora tenha resolvido o problema do alias, mas o ponto aqui é explicar como aliases funcionam (ou deixam de funcionar).