Como usar ORDER BY antes de GROUP BY no MySQL

Nesse post quero mostrar a você um truque de como usar ORDER BY antes de GROUP BY no MySQL – Como mudar a ordem no agrupamento.

Sabe aqueles coisas que fazem a gente quebrar a cabeça, toma um tempo de pesquisa, monte de testes e parece que nada funciona.

Geralmente, a gente acaba resolvendo essas coisas de uma forma simples, e as vezes até óbvia.

Então, olha a situação que passei aqui com um projeto de um cliente que é um sistema integrado com o WordPress.

Eles tem uma tabela de faturas e eu tinha os seguintes dados:

id data_vencimento tipo subtipo obs metodo id_gateway id_gateway_carne
613 2021-10-01 assinaturas adesao Assinatura do Plano PLANO ESSENCIAL boleto pay_7895303835179531
629 2022-09-28 assinaturas mensalidade Parcela 12 de 12. carne pay_7981416104016304 ins_000004302035
630 2022-08-28 assinaturas mensalidade Parcela 11 de 12. carne pay_0081214048722265 ins_000004302035
631 2022-07-28 assinaturas mensalidade Parcela 10 de 12. carne pay_9122622527213622 ins_000004302035
632 2022-06-28 assinaturas mensalidade Parcela 9 de 12. carne pay_8623810229282099 ins_000004302035
633 2022-05-28 assinaturas mensalidade Parcela 8 de 12. carne pay_0674774703026293 ins_000004302035
634 2022-04-28 assinaturas mensalidade Parcela 7 de 12. carne pay_7611885051824003 ins_000004302035
635 2022-03-28 assinaturas mensalidade Parcela 6 de 12. carne pay_5293743028322577 ins_000004302035
636 2022-02-28 assinaturas mensalidade Parcela 5 de 12. carne pay_4106004508788312 ins_000004302035
637 2022-01-28 assinaturas mensalidade Parcela 4 de 12. carne pay_7609326364902656 ins_000004302035
638 2021-12-28 assinaturas mensalidade Parcela 3 de 12. carne pay_6414323469614363 ins_000004302035
639 2021-11-28 assinaturas mensalidade Parcela 2 de 12. carne pay_0540964003353301 ins_000004302035
640 2021-10-28 assinaturas mensalidade Parcela 1 de 12. carne pay_0196847040996473 ins_000004302035

Eu criei então uma rotina onde o usuário se cadastra e faz a assinatura de um dos planos e isso gera um boleto de adesão.

Em seguida, quando esse usuário/cliente paga essa fatura, recebo uma notificação via webhook (api) do gateway e o sistema então gerar um carnê de 12 parcelas.

Contudo, meu cliente solicitou que não fossem mostradas as 12 faturas do carnê, mas apenas a primeira parcela subsequente à adesão.

O usuário poderia depois ter um link para visualizar as demais faturas se quisesse.

Desse modo, tivemos que fazer o agrupamento usando o único campo que poderia ser usada nesse caso, o id_gateway_carne.

Ficou assim no sistema:

Entretanto, você vai reparar que na listagem funcionou o agrupamento, mas contrariamente, ele mostrava sempre a última parcela do carnê.

Então, como usar ORDER BY antes de GROUP BY?

Bem, você deve saber que o ORDER BY vem depois do GROUP BY em uma query com essas cláusulas, certo?

E é por isso que nos resultados sempre mostrava assim, quando a gente rodava a seguinte query:

SELECT * FROM prfx_faturas WHERE tipo = 'assinaturas' AND id_auxiliar = 123 GROUP BY id_gateway_carne

Adicionar um ORDER BY ali no final da consulta não interferia em nada em relação ao objetivo que tínhamos.

Então, depois de umas pesquisas começamos a chegar em uma solução – veja essa query e o resultado a seguir:

SELECT MAX(id) MaxID, id, data_vencimento, tipo, subtipo, obs, metodo, id_gateway, id_gateway_carne
    FROM prfx_faturas
    WHERE id_auxiliar = 123
    GROUP BY id_gateway_carne

O resultado:

MaxID id data_vencimento tipo subtipo obs metodo id_gateway id_gateway_carne
613 613 2021-10-01 assinaturas adesao Assinatura do Plano PLANO ESSENCIAL boleto pay_7895303835179531
640 629 2022-09-28 assinaturas mensalidade Parcela 12 de 12. carne pay_7981416104016304 ins_000004302035

Perceba que o id do agrupamento das faturas e a data_vencimento eram realmente da última parcela, mas usamos a função MAX para pegar o id máximo no caso.

Em alguns casos, você pode querer usar a função min ou uma outra para obter algum valor que possa ser usado como referência para a ordenação.

Enfim…

Agora, tendo esse id posso colocar essa consulta dentro de outra para chegar no resultado que eu gostaria.

Então, fiz da seguinte forma:

SELECT p1.id, p1.data_vencimento, p1.tipo, p1.subtipo, p1.obs, p1.metodo, p1.id_gateway, p1.id_gateway_carne 
FROM prfx_faturas p1
INNER JOIN
(
    SELECT MAX(id) MaxID
    FROM prfx_faturas
    WHERE id_auxiliar = 123
    GROUP BY id_gateway_carne
) p2
  ON p1.id = p2.MaxID
order by p1.id ASC

E o resultado foi:

id data_vencimento tipo subtipo obs metodo id_gateway id_gateway_carne
613 2021-10-01 assinaturas adesao Assinatura do Plano PLANO ESSENCIAL boleto pay_7895303835179531
640 2021-10-28 assinaturas mensalidade Parcela 1 de 12. carne pay_0196847040996473 ins_000004302035

Então, conseguimos mostrar certinho, como o cliente solicitou.

Ah… E como estamos usando o WordPress, rodamos esse SQL usando $wpdb->get_results($sql).

Espero que isso ajude você aí…

Nos vemos no próximo post!

Grande abraço,

DEIXE UMA RESPOSTA

Escrava seu comentário!
Insira seu nome aqui

Esse site utiliza o Akismet para reduzir spam. Aprenda como seus dados de comentários são processados.