Criando um ranking com SQL

Aprenda como montar um ranking e extrair qualquer posição

Neste artigo você aprenderá como extrair qualquer posição de um ranking.

O exemplo que será utilizado neste artigo é uma tabela de funcionários e seus respectivos salários. Vamos criar uma tabela para guardar as informações que vamos utilizar neste exemplo.

//SQL Server

CREATE TABLE funcionarios

(

id INT IDENTITY(1,1) PRIMARY KEY,

nome VARCHAR(150),

salario Numeric( 18,2 )

);

//MySQL

CREATE TABLE funcionarios (

id INT(6) UNSIGNED AUTO_INCREMENT PRIMARY KEY,

nome VARCHAR(150) NOT NULL,

salario DECIMAL(18, 2)

)

Agora vamos inserir alguns registros de testes:

INSERT INTO funcionarios (nome, salario) VALUES ('João', 2000 );

INSERT INTO funcionarios (nome, salario) VALUES ('Lucas', 2500 );

INSERT INTO funcionarios (nome, salario) VALUES ('Matheus', 3000 );

INSERT INTO funcionarios (nome, salario) VALUES ('Thiago', 3500 );

INSERT INTO funcionarios (nome, salario) VALUES ('Paulo', 3500 );

INSERT INTO funcionarios (nome, salario) VALUES ('Simão', 4500 );

Se você quiser saber qual é o maior salário, pode utilizar a função MAX, e se deseja saber qual é o menor salário, pode utilizar a função MIN

SELECT MAX(salario) as maior_salario FROM funcionarios

SELECT MIN(salario) as menor_salario FROM funcionarios

O que desejamos saber não é apenas o maior e o menor valor, mas saber quem é o funcionário. 

Os exemplos a seguir vão utilizar o SQL Server. 

Vamos utilizar a função ROW_NUMBER() para numerar os resultados e informar que a ordenação é com base no campo salário, este campos será ordenado por ordem decrescente de salário, para trazer primeiro os maiores valores. Para saber quem ganha o maior salário,  basta fazer desta forma:

SELECT id, nome, salario

FROM

(

Select id, nome, salario, ROW_NUMBER() OVER(Order by salario DESC) as ordem

from   funcionarios

) DT

WHERE DT.ordem = 1 ;

Perceba que neste exemplo fizemos uma consulta para criar o campo ordem, e depois, sobre esta consulta, fizemos uma segunda consulta para poder utilizar o campo que foi criado na primeira consulta (o campo "ordem"), tomando este campo como referência, filtramos pelo registro que tem o campo "ordem" com o valor 1. Como os registros foram ordenados por ordem de salário, vamos ter como resposta o registro (ou registros) que possuem o maior salário.

Se você quiser saber quem tem o segudo maior salário, bastaria fazer o seguinte:

SELECT id, nome, salario

FROM

(

Select id, nome, salario, ROW_NUMBER() OVER(Order by salario DESC) as ordem

from   funcionarios

) DT

WHERE DT.ordem = 2 ;

E se for necessário saber quem tem o menor salário? Para resolver este problema, vamos mudar o critério de ordenação utilizado para criar o campo ordem

SELECT id, nome, salario

FROM

(

Select id, nome, salario, ROW_NUMBER() OVER(Order by salario) as ordem

from   funcionarios

) DT

WHERE DT.ordem = 1 ;

Outro recurso muito útil na hora de criar rankings é verificar quais os maiores valores repetidos. Perceba que em nosso exemplo, o valor 3500 é o segundo maior salário, e este valor é compartilhado por dois funcionários. Quando executamos a nossa consulta para ver quem ocupava o segundo lugar, o resultado foi apenas 1 registro. Isso porque a função ROW_NUMBER aplica um número único para cada registro.

Para resolver este novo problema, vamos substituir ROW_NUMBER e utilizar a função DENSE_RANK 

SELECT id, nome, salario

FROM

(

Select id, nome, salario, DENSE_RANK() OVER(Order by salario DESC) as ordem

from   funcionarios

) DT

WHERE DT.ordem = 2 ;

Desta forma, ao pesquisar pelo segundo maior salário, vamos ter como resultado dois funcionários, que é o resultado que estavamos esperando.

Como nossa tabela de testes tem apenas 6 registros, foi fácil saber qual era a posição que tinha os valores repetidos. Caso você queira saber quais as posições que tem valores repetidos, será necessário agrupar os resultados.

SELECT ordem

FROM

(

Select id, nome, salario, DENSE_RANK() OVER(Order by salario DESC) as ordem

from   funcionarios

) DT

group by ordem having count(*) > 1

order by ordem

Caso você utilize o MySQL, estas funções existem nas versões superiores a 8. Se a sua versão é inferior a versão 8, pode chegar no mesmo resultado utilizando as consultas a seguir.

Para row_number():

SELECT id, nome, salario, ordem from (

Select id, nome, salario, (@row_number:=@row_number + 1) as ordem

from   funcionarios,  (SELECT @row_number:=0) AS t

order by salario DESC

) DT

WHERE ordem = 1

Para dense_rank():

SELECT id, nome, salario, ordem from(

SELECT id, nome, salario, 

CASE 

WHEN @prevRank = salario THEN @curRank 

WHEN @prevRank := salario THEN @curRank := @curRank + 1

END AS ordem

FROM funcionarios F, 

(SELECT @curRank :=0, @prevRank := NULL) r

ORDER BY salario DESC

) A WHERE ordem = 2

 

Quer conferir mais dicas sobre banco de dados? Clique aqui e veja mais dicas!