我有一张学生分数表,如下:
SrNo Class Name Marks
1 1A Student1 67
2 1A Student2 62
3 1A Student3 65
4 1A Student4 78
5 1A Student5 28
6 1B Student6 57
7 1B Student7 65
8 1B Student8 85
9 1B Student9 18
10 1B Student10 8
我希望每个类的结果为3行,包括最高,最低和平均标记。
理想的结果是:
SrNo Class Student Marks
4 1A Student4 78
5 1A Student5 28
2 1A Student2 62
8 1B Student8 85
10 1B Student10 8
6 1B Student6 57
答案 0 :(得分:5)
您可以将ROW_NUMBER
和聚合函数与OVER
组合使用。
ROW_NUMBER() OVER(PARTITION BY Class ORDER BY ABS(Marks - AvgMarks))
获得一个学生,其分数最接近该班的平均分。
<强>查询强>
;WITH CTE AS
(
SELECT
MAX(Marks)OVER(PARTITION BY Class) MaxMarks,
MIN(Marks)OVER(PARTITION BY Class) MinMarks,
AVG(Marks)OVER(PARTITION BY Class) AvgMarks,
[SrNo], [Class], [Name], [Marks]
FROM Class
), CTEAvg as
(
SELECT [SrNo], [Class], [Name], [Marks],MaxMarks,MinMarks,
ROW_NUMBER() OVER(PARTITION BY Class ORDER BY ABS(Marks - AvgMarks)) ClosestAvg
FROM CTE
)
SELECT [SrNo], [Class], [Name], [Marks]
FROM CTEAvg
WHERE [Marks] = MaxMarks
OR [Marks] = MinMarks
OR ClosestAvg = 1;
<强>输出强>
| SrNo | Class | Name | Marks |
|------|-------|-----------|-------|
| 2 | 1A | Student2 | 62 |
| 4 | 1A | Student4 | 78 |
| 5 | 1A | Student5 | 28 |
| 6 | 1B | Student6 | 57 |
| 10 | 1B | Student10 | 8 |
| 8 | 1B | Student8 | 85 |
答案 1 :(得分:0)
这是针对类别的最高/最低分数,
Select Class, Student, Marks from
(
Select row_number() over (order by class, marks desc) as row_id,
class,
student,
marks
from student
)T
where row_id = 1 or row_id =
(
select max(row_id) from t
)
答案 2 :(得分:0)
您可以尝试这样的方法来实现它:
-- Create demo data
CREATE TABLE #temp(SrNo int, Class nvarchar(5), Name nvarchar(50), Marks int)
INSERT INTO #temp(SrNo, Class, Name, Marks)
VALUES (1,'1A','Student1',67),
(2,'1A','Student2',62),
(3,'1A','Student3',65),
(4,'1A','Student4',78),
(5,'1A','Student5',28),
(6,'1B','Student6',57),
(7,'1B','Student7',65),
(8,'1B','Student8',85),
(9,'1B','Student9',18),
(10,'1B','Student10',8)
-- your part
SELECT t.*
FROM (
SELECT Class,
MIN(Marks) as min_marks,
AVG(Marks) as avg_marks,
MAX(Marks) as max_marks
FROM #temp
GROUP BY class
) as data
OUTER APPLY (
SELECT TOP 1 t.marks as nearest_avg
FROM #temp as t
WHERE t.class = data.Class
ORDER BY CASE WHEN data.avg_marks-marks >= 0 THEN data.avg_marks-Marks ELSE Marks-data.avg_marks END
) as avg_data
INNER JOIN #temp as t
ON t.Class = data.Class
AND(
t.Marks = data.min_marks
OR t.marks = avg_data.nearest_avg
OR t.marks = data.max_marks
)
-- Cleanup
DROP TABLE #temp