这是桌子:
StuId Name Class Marks
-----------------------------
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
我需要输出表为:
StuId Name Class Marks Rank
-----------------------------------
2003 aman X-A 91 1
2005 ankita X-A 89 2
2010 Aakash X-A 87 3
2011 Cyril X-A 87 3
2016 Katie X-B 93 1
2012 Bala X-B 87 2
2013 Sara X-C 89 1
2014 Katlyn X-C 89 1
2015 Casy X-C 87 3
我为其执行了以下查询:
SELECT *,
RANK() OVER (PARTITION BY Class ORDER BY Marks DESC) AS Rank
FROM StudentTable;
但是在不使用Rank()
的情况下如何获得相同的结果?
答案 0 :(得分:3)
您可以尝试使用相关的子查询,该子查询使用相同的“类”中的较高或相等的标记来计数。
SELECT *,
(
SELECT COUNT(DISTINCT s2.Marks)
FROM StudentTable s2
WHERE s2.Class = s.Class
AND s2.Marks >= s.Marks
) AS Rank
FROM StudentTable s
ORDER BY Class, Marks DESC;
可以找到测试 db <>小提琴here
但是RANK会更有效。
答案 1 :(得分:1)
换句话说,学生的排名将是分数高于hir 加1 的学生人数。例如。得分为87分的学生排在前面89位和91位,因此他们排名第3:
SELECT t.*, (
SELECT COUNT(*)
FROM StudentTable AS x
WHERE x.Class = t.Class
AND x.Marks > t.Marks
) + 1 AS Rank
FROM StudentTable AS t
ORDER BY t.Class, Rank
答案 2 :(得分:0)
我正在使用身份密钥创建临时表以便对行进行排序。当对具有INSERT
列的表执行IDENTITY
时,SQL引擎会遵守ORDER BY
子句。
然后,我使用递归CTE为每一行创建一个RANK
列。这个想法很简单:
class
,请重新排名class
相同且marks
相同-使用相同的等级(增加当前等级的计数器)class
相同而marks
不相同,则用1
增加等级并重置等级计数器我们正在使用这样的计数器来实现RANK
的行为,对于DENSE_RANK
,我们不需要这样的计数器。
所以,代码是这样的:
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;
注意,这是一个主意。您可以将CASE WHEN
语句替换为IIF
,也可以用其他方式编写CTE(无需使用第二个表来存储数据)。
祝你好运。
答案 3 :(得分:0)
以下内容仅适用于count,尽管您最好使用rank:
COUNT(*) OVER (PARTITION BY Class ORDER BY Marks ASC RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW)
- COUNT(*) OVER (PARTITION BY Class,Marks) + 1
或者,您可以使用相关子查询,该查询仅使用纯计数,但速度较慢:
(SELECT COUNT(*) FROM StudentTable AS CountMe WHERE StudentTable.Class = CountMe.Class AND StudentTable.Marks > CountMe.Marks) + 1 AS Rank