SQL - 与 SUM 的 HAVING + MAX 相交

SQL - INTERSECT with HAVING + MAX of a SUM

我参加了数据库期末考试,在解决一些样题时遇到了一些问题。

我有 2 个表之间的多对多关系。

Player                    PlayerTournament               Tournament
-------                  --------------------           -------------------
pk id_player             fk id_player                   pk id_tournament
name                     fk id_tournament               name
rank                     year                           city
country                  victories                      court_surface
                                                        tournament_type

我要做的是:

1).列出 2016 年在红土锦标赛中至少赢得一场比赛但未参加任何草地锦标赛的球员(姓名和国家/地区)。

2).列出胜利次数最多的球员(姓名、国家、胜利总数)。

我在想这样的事情:

1. SELECT P.NAME, P.COUNTRY
FROM Player P INNER JOIN PlayerTournament PT
ON P.ID_PLAYER= PT.ID_PLAYER
INNER JOIN Tournament T
ON T.ID_TOURNAMENT= PT.ID_TOURNAMENT
WHERE T.COURT_SURFACE="clay"
GROUP BY (something)
HAVING SUM(PT.VICTORIES)>=1
INTERSECT
(same select and inner joins)
WHERE T.COURT_SURFACE="grass"
GROUP BY (something)
HAVING COUNT(ID_PLAYER)=0

2.SELECT P.NAME, P.COUNTRY, SUM(PT.VICTORIES)
FROM Player P INNER JOIN PlayerTournament PT
ON P.ID_PLAYER= PT.ID_PLAYER
GROUP BY ...
HAVING sum of victories = max sum of victories 

我不知道我认为问题的方式是否正确,我需要有关 "having" 语句的帮助。

Q1:INTERSECT 将不起作用,因为 COUNT(ID_PLAYER) 永远不会为 NULL。 您必须在没有 HAVING 的情况下切换到 EXCEPT

此类查询的另一种标准解决方案(相同 Select 但条件不同)利用 条件聚合 ,其中两个条件都移入不同的 CASE:

SELECT P.NAME, P.COUNTRY
FROM Player P INNER JOIN PlayerTournament PT
ON P.ID_PLAYER= PT.ID_PLAYER
INNER JOIN Tournament T
ON T.ID_TOURNAMENT= PT.ID_TOURNAMENT
WHERE T.COURT_SURFACE IN ('clay', 'grass')
GROUP BY (something)
HAVING SUM(CASE WHEN T.COURT_SURFACE = 'clay' THEN PT.VICTORIES END)>=1
 AND COUNT(CASE WHEN T.COURT_SURFACE = 'grass' THEN PT.ID_PLAYER END)=0

问题 2:这似乎要求 每个国家/地区的最佳球员,但您不能直接写出您的 having,因为嵌套聚合很少被允许。您可以改用相关子查询:

WITH cte AS
 (
   SELECT P.NAME, P.COUNTRY, SUM(PT.VICTORIES) AS sumVic
   FROM Player P INNER JOIN PlayerTournament PT
   ON P.ID_PLAYER= PT.ID_PLAYER
   GROUP BY ...
 )
SELECT *
FROM cte AS t1
WHERE sumVic = 
 ( SELECT MAX(sumVic)
   FROM cte AS t2 
   WHERE t1.ID_PLAYER = t2.ID_PLAYER
 )

使用更现代的Windowed Aggregate Functions您可以在同一级别进行 MAX 计算:

WITH cte AS
 (
   SELECT P.NAME, P.COUNTRY, SUM(PT.VICTORIES) AS sumVic,
      MAX(SUM(PT.VICTORIES)) OVER (PARTITION BY P.COUNTRY) AS maxVic
   FROM Player P INNER JOIN PlayerTournament PT
   ON P.ID_PLAYER= PT.ID_PLAYER
   GROUP BY ...
 )
SELECT *
FROM cte AS t1
WHERE sumVic = maxVic