Applying grouped ranking using ROW_NUMBER - sql-server

I m Looking for ways to assign the row numbers as below for the table
Roll No Name Score
1 ABC 10
1 ABC 10
1 DEF 8
2 ASC 9
2 YHN 4
3 IOP 5
3 YHN 4
I m looking for a way to assign the roll no as Rownumber()
Roll No Name Score Row_Number
1 ABC 10 1
1 ABC 10 2
1 DEF 8 3
2 ASC 9 1
2 YHN 4 2
3 IOP 5 1
3 YHN 4 2
I m trying to work around with Row_number() , it is isnt working . ANy inputs on this world be great :)
Thanks !!!!

SELECT [Roll No], Name, Score, [ROW_NUMBER] =
ROW_NUMBER() OVER (PARTITION BY [Roll No] ORDER BY Score DESC)
FROM dbo.table
ORDER BY [Roll No], [ROW_NUMBER];
If you later decide that you want to handle ties in a different way, play with using RANK() or DENSE_RANK() in place of ROW_NUMBER()...

Related

Create column with ranking order [duplicate]

I am working on a query for SQL Server 2005 that needs to return data with two 'index' fields. The first index 't_index' should increment every time the 'shade' column changes, whilst the second index increments within the partition of the values in the 'shade' column:
t_index s_index shade
1 1 A
1 2 A
1 3 A
1 4 A
1 5 A
2 1 B
2 2 B
2 3 B
2 4 B
2 5 B
To get the s_index column I am using the following:
Select ROW_NUMBER() OVER(PARTITION BY [shade] ORDER BY [shade]) as s_index
My question is how to get the first index to only increment when the value in the 'shade' column changes?
That can be accomplished with the DENSE_RANK() function:
DENSE_RANK() OVER(Order By [shade]) as t_index
You can try to use DENSE_RANK() for that:
SELECT
shade,
s_index = ROW_NUMBER() OVER(PARTITION BY [shade] ORDER BY [shade]),
t_index = DENSE_RANK() OVER (ORDER BY [shade])
FROM dbo.YourTableNameHEre
Gives output:
shade s_index t_index
A 1 1
A 2 1
A 3 1
A 4 1
A 5 1
B 1 2
B 2 2
B 3 2
B 4 2
B 5 2

DENSE_RANK() OVER ( PARTITION by

I've: DENSE_RANK() OVER ( PARTITION BY state ORDER BY population desc) as ranking
I'd like to skip the first 10 results of my ranking and limit it to 50 results per state. Is this possible?
so:
with data(state, pop) as (
select * from values
(1,10),
(1,10),
(1,11),
(1,12),
(2,10),
(2,11),
(2,12),
(2,12)
)
select d.*
,DENSE_RANK() OVER ( PARTITION BY state ORDER BY pop desc) as ranking
from data as d
gives:
STATE
POP
RANKING
2
12
1
2
12
1
2
11
2
2
10
3
1
12
1
1
11
2
1
10
3
1
10
3
so we can use QAULIFY to only keep those >= 3 to avoid the first "2"
select d.*
,DENSE_RANK() OVER ( PARTITION BY state ORDER BY pop desc) as ranking
from data as d
qualify ranking >= 3
STATE
POP
RANKING
2
10
3
1
10
3
1
10
3
but this shows, as we had 4 per set, we have removed 2,3 respectively from the two sets.
This can also be down with the DENSE_RANK in the QUALIFY like:
select d.*
from data as d
qualify DENSE_RANK() OVER ( PARTITION BY state ORDER BY pop desc) >= 3
STATE
POP
2
10
1
10
1
10
thus skipping the 10's and take things up to the 50's can be done with:
qualify DENSE_RANK() OVER ( PARTITION BY state ORDER BY pop desc) between 10 and 50
but if you really want the absolute first 10 skipped and 50 or less rows, you should use a non-duplicating rank like ROW_NUMBER, thus to skip 10 and take make 50 per state:
qualify ROW_NUMBER() over (PARTITION by state order by pop desc) between 10 and 60

Return a Column as string based on a other column set

Table Structure
SNO StudenNumber Subject N0 Remark
1 10 1 Good
2 10 2 Average
3 10 3 Very Good
4 10 4 Poor
5 10 5 Very Poor
6 10 1 Very Good
7 10 2 Good
8 10 3 Outstanding
9 10 4 Poor
10 10 5 Very Poor
11 10 1 Very Good
12 10 2 Good
13 10 3 Outstanding
14 10 4 Good
15 10 5 Poor
The following is the one particular student performance on a particular year on term 1, term 2, and term 3 exams.
Expected result is:
[1: Good, 2: Average, 3: Very Good, 4: Poor, 5: Very Poor],
[1: Very Good, 2 : Good, 3: Outstanding 4 : Poor, 5:Very Poor],
[1: Very Good, 2 : Good, 3: Outstanding 4 : Good, 5:Poor]
You can use STRING_AGG and RowNumber Function to attain this:
SELECT STRING_AGG(CONCAT(M.SUBJECT_NO,' : ',M.REMARK),',')WITHIN GROUP (ORDER BY M.S_NO)
FROM #T M INNER JOIN (
SELECT S_NO,
ROW_NUMBER() OVER(PARTITION BY SUBJECT_NO ORDER BY SUB_NO) AS ROW_NUMBER
FROM #T)S ON S.S_NO=M.S_NO
GROUP BY S.ROW_NUMBER
For SQL 2008: You can achieve this using Stuff
;WITH CTE AS
(SELECT ROW_NUMBER() OVER(PARTITION BY SUBJECT_N0 ORDER BY SUBJECT_N0) AS
ROW_NUMBER ,REMARK,SUBJECT_N0 FROM #T )
SELECT DISTINCT STUFF((SELECT CONCAT(',',T1.SUBJECT_N0,': ',REMARK)
FROM CTE T1
WHERE T1.ROW_NUMBER=CTE.ROW_NUMBER
FOR XML PATH('')),1,1,'') AS CONCATENATION FROM CTE

Top 9 Distinct records after using sub query for cumulative sum

I have SQL data table with following data structure
ID Hrly Hshed Dust_removal_to_done Dust_removal_done Update_datetime
2 ER MGS 4 4 2009-05-05
3 ER AQ 4 2 2009-05-05
4 SR ANDA 4 4 2009-05-05
5 ECR HOME 5 5 2009-05-05
6 NR GZB 5 5 2009-05-05
7 NR LDH 5 5 2009-05-05
8 NCR JHS 5 5 2009-05-05
9 NCR CNB 5 5 2009-06-05
10 SCR LGD 5 5 2009-06-05
11 SCR LGD 5 5 2009-05-05
the data is fed by users on daily basis.
Further I am using a stored procedure for cumulative sum of 'Dust_removal_done' as
ALTER PROCEDURE [dbo].[RAP_regular] as
SELECT Hshed, HRly, Dust_removal_to_done, Dust_removal_done, (SELECT SUM(Dust_removal_done) FROM TPHRAP_regular t2
where t2.Hshed = TPHRAP_regular.Hshed and t2.Update_datetime <= TPHRAP_regular.Update_datetime) as cumulative_dust_removal
FROM TPHRAP_regular
This stored procedure is giving me result as under
Hshed Hrly Dust_removal_to_done Dust_removal_done cumulative_dust_removal
MGS ER 4 4 4
AQ ER 4 2 2
ANDA SR 4 4 4
HOME ECR 5 5 5
GZB NR 5 5 5
LDH NR 5 5 5
JHS NCR 5 5 5
CNB NCR 5 5 5
LGD SCR 5 5 10
LGD SCR 5 5 5
This is working fine. Now the issue is that there are only 9 Hsheds and therefore I want to display only 9 latest records (unique Hshed along with cumulative column) in my grid view as final result so that no Hshed will repeate in the table. How to achieve this? please help.
You need to change your stored procedure(Has to be in it since you are discarding the date field in it).
You can use ROW_NUMBER() window function to filter only the latest records, like this:
SELECT Hshed,HRly,Dust_removal_to_done,Dust_removal_done,cumulative_dust_removal
FROM(
SELECT Hshed, HRly, Dust_removal_to_done, Dust_removal_done,
(SELECT SUM(Dust_removal_done) FROM TPHRAP_regular t2
where t2.Hshed = TPHRAP_regular.Hshed
and t2.Update_datetime <= TPHRAP_regular.Update_datetime) as cumulative_dust_removal,
ROW_NUMBER() OVER (PARTITION BY Hshed ORDER BY Update_datetime DESC) as rnk
FROM TPHRAP_regular)
WHERE rnk = 1
EDIT: You should also use SUM() OVER(..) for cumulative sum , no need to select from the table twice:
SELECT t.Hshed,
t.HRly,
t.Dust_removal_to_done,
t.Dust_removal_done,
t.cumulative_dust_removal
FROM (SELECT Hshed,
HRly,
Dust_removal_to_done,
Dust_removal_done,
SUM(Dust_removal_done) OVER(PARTITION BY Hshed ORDER BY Update_datetime) as cumulative_dust_removal,
ROW_NUMBER() OVER(PARTITION BY Hshed ORDER BY Update_datetime DESC) as rnk
FROM TPHRAP_regular) t
WHERE t.rnk = 1

TSQL - Difficult Grouping

Please see fiddle: http://sqlfiddle.com/#!6/e6768/2
I have data, like below:
DRIVER DROP
1 1
1 2
1 ReturnToBase
1 4
1 5
1 ReturnToBase
1 6
1 7
2 1
2 2
2 ReturnToBase
2 4
I am trying to group my data, so for each driver, each group of return to bases have a grouping number.
My output should look like this:
DRIVER DROP GROUP
1 1 1
1 2 1
1 ReturnToBase 1
1 4 2
1 5 2
1 ReturnToBase 2
1 6 3
1 7 3
1 ReturnToBase 3
2 1 1
2 2 1
2 ReturnToBase 1
2 4 2
I've tried getting this result with a combination of windowed functions but I've been miles off so far
Below is what I had so far, it isn't supposed to be functional I was trying to figure out how it could be done, if it's even possible.
SELECT
ROW_NUMBER() OVER (Partition BY Driver order by Driver Desc) rownum,
Count(1) OVER (Partition By Driver Order By Driver Desc) counter,
Count
DropNo,
Driver,
CASE DropNo
WHEN 'ReturnToBase' THEN 1 ELSE 0 END AS EnumerateRound
FROM
Rounds
You can use the following query:
SELECT id, DRIVER, DROPno,
1 + SUM(flag) OVER (PARTITION BY DRIVER ORDER BY id) -
CASE
WHEN DROPno = 'ReturnToBase' THEN 1
ELSE 0
END AS grp
FROM (
SELECT id, DRIVER, DROPno,
CASE
WHEN DROPno = 'ReturnToBase' THEN 1
ELSE 0
END AS flag
FROM rounds ) AS t
Demo here
This query uses windowed version of SUM with ORDER BY in the OVER clause to calculate a running total. This version of SUM is available from SQL Server 2012 onwards AFAIK.
Fiddling a bit with this running total value is all we need in order to get the correct GROUP value.
EDIT: (credit goes to #Conrad Frix)
Using CROSS APPLY instead of an in-line view can considerably simplify things:
SELECT id, DRIVER, DROPno,
1 + SUM(x.flag) OVER (PARTITION BY DRIVER ORDER BY id) - x.flag
FROM rounds
CROSS APPLY (SELECT CASE WHEN DROPno = 'ReturnToBase' THEN 1 ELSE 0 END) AS x(flag)
Demo here
Added a sequential ID column to your example for use in a recursive CTE:
with cte as (
select ID,DRIVER,DROPno,1 as GRP
FROM rounds
where ID = 1
union all
select a.ID
,a.DRIVER
,a.DROPno
,case when b.DROPno = 'ReturnToBase'
or b.DRIVER <> a.DRIVER then b.GRP + 1
else b.GRP end
from rounds a
inner join cte b
on a.ID = b.ID + 1
)
select * from cte
SQL Fiddle

Resources