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
我参加了数据库期末考试,在解决一些样题时遇到了一些问题。
我有 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