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
classis 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.