如何修改SQL查询以计算2021-2022常规赛每位球员最近5场比赛的每28分钟平均数据
如何修改SQL查询以计算2021-2022常规赛每位球员最近5场比赛的每28分钟平均数据
嘿,我完全理解你现在的困扰——既要精准拿到每个球员2021-2022常规赛的最近5场比赛,又要正确算出每28分钟的平均数据,之前的查询确实在这两个点上踩了坑。咱们一步步把它修正过来:
核心问题分析
你之前的两个版本都有明显的问题:
- 第一个查询没有限定赛季范围,也没筛选每个球员的最近5场,
HAVING AVG(MIN) >=28只是过滤了平均每场上场28分钟以上的球员,但不是针对最近5场的统计。 - 第二个查询用
GROUP BY game_date再加LIMIT 5,只返回了5行数据,而不是每个球员的5场比赛。
修正后的完整查询
我们用窗口函数来标记每个球员的最近5场比赛,再用正确的逻辑计算每28分钟的数据:
-- 第一步:先筛选出2021-2022常规赛中每个球员的最近5场比赛 WITH player_last_5_games AS ( SELECT PLAYER_ID, PLAYER_NAME, FGM, FGA, FG3M, FG3A, FTM, FTA, OREB, DREB, REB, AST, TOV, STL, BLK, BLKA, PF, PFD, PTS, PLUS_MINUS, FG_PCT, FG3_PCT, FT_PCT, MIN FROM ( SELECT *, -- 给每个球员的比赛按日期倒序排名,最近的比赛排第1 ROW_NUMBER() OVER (PARTITION BY PLAYER_ID ORDER BY game_date DESC) AS game_rank FROM sis_basketball_research.nba_player_game_logs -- 务必筛选2021-2022常规赛,根据表实际字段调整(如果没有season字段,可用game_date范围替代) WHERE season = '2021-2022' AND game_type = 'Regular Season' ) ranked_games -- 只保留每个球员的前5场(最近的5场) WHERE game_rank <= 5 ) -- 第二步:计算每28分钟的平均数据 SELECT PLAYER_ID, PLAYER_NAME, -- 关键逻辑:总数据 / 总上场分钟数 * 28,这是NBA标准的每N分钟换算方式 -- 用NULLIF避免出现除以0的错误(比如球员5场都没上场的极端情况) SUM(FGM) / NULLIF(SUM(MIN), 0) * 28 AS FGM_per_28min, SUM(FGA) / NULLIF(SUM(MIN), 0) * 28 AS FGA_per_28min, SUM(FG3M) / NULLIF(SUM(MIN), 0) * 28 AS FG3M_per_28min, SUM(FG3A) / NULLIF(SUM(MIN), 0) * 28 AS FG3A_per_28min, SUM(FTM) / NULLIF(SUM(MIN), 0) * 28 AS FTM_per_28min, SUM(FTA) / NULLIF(SUM(MIN), 0) * 28 AS FTA_per_28min, SUM(OREB) / NULLIF(SUM(MIN), 0) * 28 AS OREB_per_28min, SUM(DREB) / NULLIF(SUM(MIN), 0) * 28 AS DREB_per_28min, SUM(REB) / NULLIF(SUM(MIN), 0) * 28 AS REB_per_28min, SUM(AST) / NULLIF(SUM(MIN), 0) * 28 AS AST_per_28min, SUM(TOV) / NULLIF(SUM(MIN), 0) * 28 AS TOV_per_28min, SUM(STL) / NULLIF(SUM(MIN), 0) * 28 AS STL_per_28min, SUM(BLK) / NULLIF(SUM(MIN), 0) * 28 AS BLK_per_28min, SUM(BLKA) / NULLIF(SUM(MIN), 0) * 28 AS BLKA_per_28min, SUM(PF) / NULLIF(SUM(MIN), 0) * 28 AS PF_per_28min, SUM(PFD) / NULLIF(SUM(MIN), 0) * 28 AS PFD_per_28min, SUM(PTS) / NULLIF(SUM(MIN), 0) * 28 AS PTS_per_28min, SUM(PLUS_MINUS) / NULLIF(SUM(MIN), 0) * 28 AS PLUS_MINUS_per_28min, -- 命中率直接取平均即可,因为单场命中率是比例值,平均更能反映整体表现 AVG(FG_PCT) AS FG_PCT_avg, AVG(FG3_PCT) AS FG3_PCT_avg, AVG(FT_PCT) AS FT_PCT_avg FROM player_last_5_games GROUP BY PLAYER_ID, PLAYER_NAME -- 可选:如果要过滤掉总上场时间为0的球员,加上这个条件 HAVING SUM(MIN) > 0;
关键细节说明
- 窗口函数ROW_NUMBER():通过
PARTITION BY PLAYER_ID确保每个球员的比赛单独排序,ORDER BY game_date DESC让最近的比赛排在最前面,然后取game_rank <=5就得到了每个球员的最近5场,完美解决了之前LIMIT 5的问题。 - 赛季筛选:一定要加
WHERE条件限定2021-2022常规赛,不然会混入其他赛季或季后赛的数据,结果就不准确了。如果你的表没有season或game_type字段,可以用game_date范围替代,比如game_date BETWEEN '2021-10-19' AND '2022-04-10'(这是2021-2022常规赛的实际起止日期)。 - 每28分钟换算逻辑:用总数据除以总上场分钟数再乘以28,这是NBA官方常用的统计方式,比单场换算后再平均更准确,因为它反映了球员在这段时间内的总产出效率。
NULLIF(SUM(MIN),0)是为了防止出现除以0的错误,避免查询报错。 - 命中率处理:命中率是单场的投篮比例,直接取平均就能反映球员在这5场的整体命中率表现,不需要换算成每28分钟的数值。
备注:内容来源于stack exchange,提问作者Pete Curaro
相关产品推荐
相关产品推荐

