web-dev-qa-db-fra.com

Comment utiliser RANK () dans SQL Server

J'ai un problème avec RANK() dans SQL Server.

Voici mon code:

SELECT contendernum,
       totals, 
       RANK() OVER (PARTITION BY ContenderNum ORDER BY totals ASC) AS xRank
FROM (
   SELECT ContenderNum,
          SUM(Criteria1+Criteria2+Criteria3+Criteria4) AS totals
   FROM Cat1GroupImpersonation
   GROUP BY ContenderNum
) AS a

Les résultats pour cette requête sont:

contendernum    totals    xRank
          1       196        1
          2       181        1
          3       192        1
          4       181        1
          5       179        1

Quel est le résultat souhaité?

contendernum    totals    xRank
          1       196        1
          2       181        3
          3       192        2
          4       181        3
          5       179        4

Je souhaite classer le résultat en fonction de totals. S'il existe la même valeur que 181, deux nombres auront la même xRank.

67
Prince Jea

Changement:

RANK() OVER (PARTITION BY ContenderNum ORDER BY totals ASC) AS xRank

à:

RANK() OVER (ORDER BY totals DESC) AS xRank

Regardez cet exemple:

SQL Fiddle DEMO

Vous voudrez peut-être aussi examiner la différence entre RANK (Transact-SQL) et DENSE_RANK (Transact-SQL) :

RANK (Transact-SQL)

Si deux rangées ou plus sont à égalité pour un rang, chacune d'entre elles reçoit la même chose rang. Par exemple, si les deux meilleurs vendeurs ont le même SalesYTD valeur, ils sont tous deux classés un. Le vendeur avec le prochain plus élevé SalesYTD est classé numéro trois, car il y a deux lignes qui sont classé plus haut. Par conséquent, la fonction RANK ne renvoie pas toujours entiers consécutifs.

DENSE_RANK (Transact-SQL)

Retourne le rang des lignes dans la partition d'un jeu de résultats, sans toute lacune dans le classement. Le rang d'une ligne est égal à un plus le nombre de rangs distincts qui viennent avant la ligne en question.

75
Adriaan Stander

Pour répondre au titre de votre question, "Comment utiliser Rank () dans SQL Server", voici comment cela fonctionne:

Je vais utiliser cet ensemble de données à titre d'exemple:

create table #tmp
(
  column1 varchar(3),
  column2 varchar(5),
  column3 datetime,
  column4 int
)

insert into #tmp values ('AAA', 'SKA', '2013-02-01 00:00:00', 10)
insert into #tmp values ('AAA', 'SKA', '2013-01-31 00:00:00', 15)
insert into #tmp values ('AAA', 'SKB', '2013-01-31 00:00:00', 20)
insert into #tmp values ('AAA', 'SKB', '2013-01-15 00:00:00', 5)
insert into #tmp values ('AAA', 'SKC', '2013-02-01 00:00:00', 25)

Vous avez une partition qui spécifie fondamentalement le groupement.

Dans cet exemple, si vous partitionnez par colonne2, la fonction rank créera des rangs pour des groupes de valeurs column2. Il y aura différents rangs pour les lignes où column2 = 'SKA' par rapport aux lignes où column2 = 'SKB' et ainsi de suite.

Les rangs sont déterminés comme suit: Le rang pour chaque enregistrement est égal à un plus le nombre de rangs qui le précèdent dans sa partition. Le rang n'incrémentera que lorsque l'un des champs que vous avez sélectionnés (autres que le ou les champs partitionnés) est différent de ceux qui le précèdent. Si tous les champs sélectionnés sont identiques, les rangs seront liés et une valeur sera attribuée aux deux.

Sachant cela, si nous voulions seulement sélectionner une valeur de chaque groupe de la deuxième colonne, nous pourrions utiliser cette requête:

with cte as 
(
  select *, 
  rank() over (partition by column2 
             order by column3) rnk
  from t

) select * from cte where rnk = 1 order by column3;

Résultat:

COLUMN1 | COLUMN2   | COLUMN3                           |COLUMN4 | RNK
------------------------------------------------------------------------------
AAA     | SKB   | January, 15 2013 00:00:00+0000    |5   | 1
AAA     | SKA   | January, 31 2013 00:00:00+0000    |15  | 1
AAA     | SKC   | February, 01 2013 00:00:00+0000   |25  | 1

SQL DEMO

16
Jared Beach

Vous devez utiliser DENSE_RANK plutôt que RANK. La seule différence est que cela ne laisse pas de lacunes. Vous ne devriez pas non plus partitionner par contender_num, sinon vous classerez chaque candidat dans un groupe séparé, donc chacun est classé au premier rang de son groupe séparé!

SELECT contendernum,totals, DENSE_RANK() OVER (ORDER BY totals desc) AS xRank FROM
(
SELECT ContenderNum ,SUM(Criteria1+Criteria2+Criteria3+Criteria4) AS totals
FROM dbo.Cat1GroupImpersonation
 GROUP BY ContenderNum
) AS a
order by contendernum

Un conseil pour l’utilisation de StackOverflow, postez s'il vous plaît DDL et des exemples de données pour que les gens puissent vous aider à utiliser moins de leur temps!

create table Cat1GroupImpersonation (
contendernum int,
criteria1 int,
criteria2 int,
criteria3 int,
criteria4 int);

insert Cat1GroupImpersonation select
1,196,0,0,0 union all select
2,181,0,0,0 union all select
3,192,0,0,0 union all select
4,181,0,0,0 union all select
5,179,0,0,0;
9
RichardTheKiwi

DENSE_RANK () est un classement sans espace, c'est-à-dire «dense». 

select Name,EmailId,salary,DENSE_RANK() over(order by salary asc) from [dbo].[Employees]

RANK () - Il contient un espace entre le rang.

select Name,EmailId,salary,RANK() over(order by salary asc) from [dbo].[Employees]
2
Debendra Dash

RANK() est bon, mais il attribue le même rang pour des valeurs égales ou similaires. Et si vous avez besoin d'un classement unique, alors ROW_NUMBER () résout ce problème.

ROW_NUMBER() OVER (ORDER BY totals DESC) AS xRank
0
Bex
SELECT contendernum,totals, RANK() OVER (ORDER BY totals ASC) AS xRank FROM
(
SELECT ContenderNum ,SUM(Criteria1+Criteria2+Criteria3+Criteria4) AS totals
FROM dbo.Cat1GroupImpersonation
 GROUP BY ContenderNum
) AS a
0
Adi

Vous avez déjà groupé par ContenderNum, inutile de partitionner à nouveau par celui-ci . Utilisez Dense_rank () et triez par totaux. En bref,

SELECT contendernum,totals, **DENSE_RANK()** 
OVER (ORDER BY totals **DESC**) 
AS xRank 
FROM
(
   SELECT ContenderNum ,SUM(Criteria1+Criteria2+Criteria3+Criteria4) AS totals
   FROM dbo.Cat1GroupImpersonation
   GROUP BY ContenderNum
) AS a
0
ajit