Solucionado (ver solução)
Solucionado
(ver solução)
2
respostas

Diferenças na consulta

Minha consulta ficou um pouco diferente, mas funcionou igual:

SELECT NOME, DATE_FORMAT(NF.DATA_VENDA,'%Y-%m') AS MES_ANO, 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_VOLUME_VENDIDO 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 NOME,MES_ANO ORDER BY NOME,MES_ANO;

Isso me gerou algumas dúvidas: 1) No vídeo o professor usa MAX(VOLUME_DE_COMPRA) por causa da junção (JOIN) de planilhas que faria um produto cartesiano pra apresentar os dados, no entanto achava que isso só ocorria no CROSS JOIN. Por isso acabei não usando MAX no volume de compra na minha consulta e mesmo assim ela funcionou, é 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)? 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? 3) Acabei não usando a subconsulta, isso piora a performance do meu código?

2 respostas
solução!

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

Obrigada pela explicação.