簡體   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