Database
 sql >> Base de Dados >  >> RDS >> Database

Como selecionar a primeira linha em cada grupo GROUP BY

Problema:


Você agrupou seus dados com GROUP BY e gostaria de exibir apenas a primeira linha de cada grupo.

Exemplo:


Nosso banco de dados tem uma tabela chamada exam_results com os dados da tabela a seguir:
first_name last_name ano resultado
João Klein 2020 40
Editar Preto 2020 43
Marcar Johnson 2019 32
Laura Verão 2020 35
Kate Smith 2019 41
Jacob Preto 2019 44
Tom Bennet 2020 38
Emily Kelly 2020 43

Para cada ano, vamos encontrar o aluno com o melhor result . Se houver dois alunos empatados como o melhor em um grupo, selecionaremos arbitrariamente um deles para exibir.

Solução:

WITH added_row_number AS (
  SELECT
    *,
    ROW_NUMBER() OVER(PARTITION BY year ORDER BY result DESC) AS row_number
  FROM exam_results
)
SELECT
  *
FROM added_row_number
WHERE row_number = 1;

O resultado é:
first_name last_name ano resultado número_linha
Jacob Preto 2019 44 1
Emily Kelly 2020 43 1

Discussão:


Primeiro, você precisa escrever um CTE no qual você atribui um número a cada linha dentro de cada grupo. Para fazer isso, você pode usar o ROW_NUMBER() função. Em OVER() , você especifica os grupos em que as linhas devem ser divididas (PARTITION BY ) e a ordem em que os números devem ser atribuídos às linhas (ORDER BY ).

Dê uma olhada no resultado da consulta interna:
SELECT
  *,
  ROW_NUMBER() OVER(PARTITION BY year ORDER BY result DESC) AS row_number
FROM exam_results;
first_name last_name ano resultado número_linha
Jacob Preto 2019 44 1
Kate Smith 2019 41 2
Marcar Johnson 2019 32 3
Emily Kelly 2020 43 1
Editar Preto 2020 43 2
João Klein 2020 40 3
Tom Bennet 2020 38 4
Laura Verão 2020 35 5

Você atribui os números de linha dentro de cada grupo (ou seja, ano). Cada linha tem um número de linha baseado no valor do result coluna. As linhas são classificadas em ordem decrescente devido ao DESC palavra-chave após ORDER BY result . Mesmo se houver várias linhas em um grupo que tenham o mesmo valor de result , as linhas ainda recebem números diferentes. Aqui, Edith Black e Emily Kelly têm o mesmo result mas números de linha diferentes. Para alterar esse comportamento e atribuir o mesmo número de linha para o mesmo resultado em um grupo, use RANK() ou DENSE_RANK() em vez de ROW_NUMBER() .

Na consulta externa, você seleciona todos os dados do CTE (added_row_number ) e use um WHERE condição para especificar qual linha exibir de cada grupo. Aqui, queremos exibir a primeira linha, então a condição é row_number = 1 .

Observe que você pode modificar facilmente a solução para obter, por exemplo, a segunda linha de cada grupo.
WITH added_row_number AS (
  SELECT
    *,
    ROW_NUMBER() OVER(PARTITION BY year ORDER BY result DESC) AS row_number
  FROM exam_results
)
SELECT
  *
FROM added_row_number
WHERE row_number = 2;

Aqui está o resultado:
first_name last_name ano resultado número_linha
Kate Smith 2019 41 2
Editar Preto 2020 43 2

Por outro lado, se você deseja obter as linhas com o segundo valor mais alto de result dentro de cada grupo, você deve usar o DENSE_RANK() função. Enquanto o ROW_NUMBER() A função cria números consecutivos para cada linha em um grupo, resultando em valores diferentes atribuídos às linhas com o mesmo resultado, o DENSE_RANK() função dá o mesmo número para as linhas com o mesmo resultado.
WITH added_dense_rank AS (
  SELECT
    *,
    DENSE_RANK() OVER(PARTITION BY year ORDER BY result DESC) AS rank
  FROM exam_results
)
SELECT
  *
FROM added_dense_rank
WHERE rank = 2;
first_name last_name ano resultado classificação
Kate Smith 2019 41 2
João Klein 2020 40 2

Você pode ver que John Klein tem o segundo maior valor de result (40) para o ano de 2020. John Klein é, na verdade, a terceira pessoa do grupo, mas os dois primeiros alunos têm o mesmo result e ambos têm rank = 1 .