[英]SQL Server - Only get a single row for each distinct value of a field
我刚从面试中回家,他们让我参加编程测试。 真正难倒我的问题之一如下:
你是一所高中的老师,负责为即将到来的全国辩论锦标赛挑选最好的辩论队。 给定以下表结构:
CREATE TABLE CompetitionResults ( StudentName NVARCHAR(255) NOT NULL, -- The student's name SchoolYear INT NOT NULL, -- The school year of the student at the time they entered the competition CompetitionDate DATE NOT NULL, -- The date of the competition CompetitionResult INT NOT NULL -- The student's final score in the competition (0 - 100) )
编写一个查询,根据他们之前的比赛结果返回即将举行的比赛的最佳候选人的姓名。
约束:
- 返回单列
StudentName
。- 每个学年 (7 - 12) 只应挑选一名学生。
- 每个返校学生今年必须参加 3 场其他比赛。
特别是最后一个限制,我遇到了最大的麻烦。 这是我在时间用完后最终提交的内容:
SELECT
StudentName AS sn,
(SELECT COUNT(*) AS NumComps, CompetitionDate FROM CompetitionResults
WHERE YEAR(CompetitionDate) = 2020 AND NumComps = 3),
SchoolYear,
CompetitionDate,
CompetitionResult
FROM CompetitionResults
WHERE CompetitionDate IN (SELECT MIN(CompetitionDate)
FROM CompetitionResults GROUP BY CompetitionDate) AND
CompetitionResult IN (SELECT MAX(CompetitionResult) FROM
CompetitionResults WHERE StudentName = sn);
为了职业发展,我希望能够在尽可能少的帮助下解决这个问题,但正如你可能会说的,我在这里真的很挣扎。 这段代码甚至无法编译,更不用说所有子查询的性能影响了! 然而,我发现它们比连接更容易编码,因此我在这里使用它们。
任何指导/提示将不胜感激。 MTIA :-)
对我来说,这基本上是聚合。 . . 有一点窗口函数:
select studentname, SchoolYear, avg_competitionscore
from (select studentname, SchoolYear, avg(competitionscore) as avg_competitionscore,
row_number() over (partition by SchoolYear order by avg(competitionscore) desc) as seqnum
from CompetitionResults cr
where year(CompetitionDate) = year(getdate())
group by studentname
having count(*) = 3
) s
where seqnum = 1;
子查询汇总每个学生的比赛,应用适当的过滤条件——针对个人比赛和总人数。 外部查询每年选择一个。
我看不出三场比赛与最好的比赛有什么关系。 我怀疑根据分数选择最好的学生的部分是一个“隐藏的要求”,用于区分仅可接受的解决方案和最佳解决方案。
我想可能有额外的逻辑来检查每年是否至少有一名候选人,但问题表明至少有一名这样的学生。
我想这可以用窗口函数来解决。 遵循一个例子 - 毕竟可能需要一些调整,但你应该明白:
DECLARE @t TABLE(
StudentName NVARCHAR(255)
,SchoolYear INT
,CompetitionDate DATE
,CompetitionResult INT
)
INSERT INTO @t VALUES
('Peter', 7, '2019-01-01', 100)
,('Peter', 8, '2020-01-01', 100)
,('Peter', 8, '2020-03-01', 100)
,('Paul', 10, '2020-01-01', 100)
,('Paul', 10, '2020-03-01', 100)
,('Paul', 10, '2020-04-01', 100)
,('Mary', 11, '2019-01-01', 100)
,('Mary', 11, '2019-02-01', 100)
,('Mary', 11, '2019-03-01', 100)
,('Jacob', 12, '2020-01-01', 100)
,('Jacob', 12, '2020-02-01', 100)
,('Jacob', 12, '2020-03-01', 100)
,('Jacob', 12, '2020-04-01', 90)
,('Jennifer', 9, '2020-03-01', 100)
,('Jennifer', 9, '2020-04-01', 100)
,('Jennifer', 9, '2020-05-01', 100)
,('Lucas', 12, '2020-03-01', 100)
,('Lucas', 12, '2020-04-01', 100)
,('Lucas', 12, '2020-05-01', 100)
;WITH cte AS(
SELECT *
,COUNT(CASE WHEN YEAR(CompetitionDate) = YEAR(GETDATE()) THEN 1 ELSE NULL END) OVER (PARTITION BY StudentName, YEAR(CompetitionDate)) AS CountCompYear
,ROW_NUMBER() OVER (PARTITION BY StudentName ORDER BY CompetitionDate DESC) AS LastCompetition
FROM @t
),
cteFilter AS(
SELECT *, ROW_NUMBER() OVER (PARTITION BY SchoolYear ORDER BY CompetitionResult DESC, StudentName ASC) AS DistStudent
FROM cte
WHERE CountCompYear = 3
AND LastCompetition = 1
)
SELECT *
FROM cteFilter
WHERE DistStudent = 1
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.