繁体   English   中英

SQL Server - 只为字段的每个不同值获取一行

[英]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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM