I am creating temporary table with identity key in order to sort the rows. When an INSERT
is performed against table with IDENTITY
column, the ORDER BY
clause is respected by the SQL engine.
Then, I am using recursive CTE to create a RANK
column for each row. The idea is simple:
- if the
class
is changed, restart the ranking
- if the
class
is the same and marks
the same - use same rank (increase counter of current rank)
- if the
class
is the same and the marks
are not, increase the rank with 1
and reset the counter of rank
We are using such counter in order to get implement RANK
behavior, for DENSE_RANK
we do not need such counter.
So, the code is like this:
DECLARE @DataSource TABLE
(
[StudID] INT
,[Name] VARCHAR(12)
,[Class] VARCHAR(12)
,[Marks] TINYINT
);
INSERT INTO @DataSource ([StudID], [Name], [Class], [Marks])
VALUES ('2003', 'aman', 'X-A', '91')
,('2005', 'ankita', 'X-A', '89')
,('2010', 'Aakash', 'X-A', '87')
,('2011', 'Cyril', 'X-A', '87')
,('2012', 'Bala', 'X-B', '87')
,('2013', 'Sara', 'X-C', '89')
,('2014', 'Katlyn', 'X-C', '89')
,('2015', 'Casy', 'X-C', '87')
,('2016', 'Katie', 'X-B', '93');
CREATE TABLE #DataSource
(
[StudID] INT
,[Name] VARCHAR(12)
,[Class] VARCHAR(12)
,[Marks] TINYINT
,[RowID] INT IDENTITY(1,1)
)
INSERT INTO #DataSource ([StudID], [Name], [Class], [Marks])
SELECT [StudID], [Name], [Class], [Marks]
FROM @DataSource
ORDER BY [Class] ASC, [Marks] DESC;
WITH DataSource AS
(
SELECT *
,1 AS [Rank]
,0 AS [RanksCount]
FROM #DataSource
WHERE [RowID] = 1
UNION ALL
SELECT DS1.*
,CASE WHEN DS1.[Class] = DS2.[Class]
THEN CASE WHEN DS1.[Marks] = DS2.[Marks] THEN DS2.[Rank] ELSE DS2.[Rank] + DS2.[RanksCount] + 1 END
ELSE 1
END
,CASE WHEN DS1.[Class] = DS2.[Class]
THEN CASE WHEN DS1.[Marks] = DS2.[Marks] THEN DS2.[RanksCount] + 1 ELSE 0 END
ELSE 0
END
FROM #DataSource DS1
INNER JOIN DataSource DS2
ON DS1.[RowID] = DS2.[RowID] + 1
)
SELECT *
FROM DataSource
ORDER BY [RowID];
DROP TABLE #DataSource;

Note, this is an idea. You can replace the CASE WHEN
statements with IIF
or you can write the CTE in different way (without using second table for storing the data).
Good luck.