2

我有一个用于保龄球中心的查询,用于按降序对所有最佳平均值进行排序。

一切都很好,除了如果一个球员在两个不同的联赛打球(或者当我没有按赛季分组,因为每个赛季后的平均数都重置了),我只想要给定球员的最佳平均数,因为我不想要重复. (同一球员在不同联赛的平均数不会累积,因此一名球员可以有多个平均数)

我以为我在 Stack Overflow 上询问后不久就解决了这个问题(这里),但最近,有人告诉我,有时查询存在一些问题,我不知道我之前是怎么没有注意到的。

问题是,即使我没有得到重复的名字并且我得到了正确的 MAX 平均值,但如果一个球员在多个联赛中打球,其他列,例如联赛名称、比赛次数和赛季并不总是正确的. 这是查询:

SELECT  PlayerID, Name, max(score)Avg, gamesCount, LeagueName, Season
    FROM( SELECT  PlayerID, Player.Name as Name, Player.Gender as Gender, ROUND(AVG(score),2) as score, COUNT(score) as gamesCount, LeagueName, Season
        FROM  Scores JOIN Players as Player USING(PlayerID)
        WHERE Score > -1 AND bowlout = 'No' AND season = '2011-2012'
        GROUP BY PlayerID, LeagueName, Season
        HAVING gamesCount >= 50
    ) as league_avg
WHERE Gender = 'Male'
GROUP BY PlayerID
ORDER BY Avg DESC LIMIT 0,50;

显然,它不起作用,因为外部查询仅按 PlayerID 分组,因此它获取玩家的最大 AVG,但其他字段,例如,如果有多个联赛,则从联盟中随机选择其他字段。他参加的联赛。

我想要的是获得与球员和他的最高平均水平相对应的联赛名称(以及所有其他信息)。

这是一个例子:

Name       |      AVG      |   LeagueName
Jones, Tom      122.56          Friday League
Smith, Adam     182.42          Super League
Smith, Adam     194.25          Friendly League
...

预期的结果是:

Name       |      AVG      |   LeagueName
Smith, Adam     194.25          Friendly League
Jones, Tom      122.56          Friday League

我得到了什么:

Name       |      AVG      |   LeagueName
Smith, Adam     194.25          *Super League*
Jones, Tom      122.56          Friday League

如您所见,Smith、Adam 的 AVG 正确,但与 Name/Avg 组合关联的联赛错误。

我尝试将外部 GROUP BY 子句更改为 PlayerID、LeagueName、Season,但这只是在每个赛季的每个联赛中重新分离,然后我再次得到重复项。除了使用其中的 Java 应用程序、获取所有结果并删除 Java 中的重复项之外,我不知道该尝试什么。显然,我宁愿第一次从 SQL 查询中得到正确的结果。

作为旁注,即使在本文前面提到过,有时查询不会有“AND season = '2011-2012'”部分,所以我也不能在不同赛季中获得同一球员的重复。

编辑:我正在使用 SQLite,以防有些人没有注意到标签。

4

3 回答 3

2

我相信这样的事情应该有效。

SELECT PlayerID,
       Name,
       Season,
       CAST( SUBSTR(MAX(stats),1,10) AS REAL) AS Average,
       CAST( SUBSTR(MAX(stats),11,10) AS INTEGER) AS GamesCount,
       SUBSTR(MAX(stats),21) AS LeagueName
  FROM (
          SELECT PlayerID,
                 Player.Name as Name,
                 Season,
                 CASE WHEN LENGTH(ROUND(AVG(score),2))-(LENGTH(CAST(AVG(score) AS INTEGER)))=2
                           THEN SUBSTR('          '||(ROUND(AVG(score),2))||'0', -10,10)
                           ELSE SUBSTR('          '||(ROUND(AVG(score),2)), -10,10)
                   END || SUBSTR('          '||COUNT(score),-10,10) || LeagueName as stats
            FROM Scores
            JOIN Players as Player USING(PlayerID)
           WHERE Score > -1
             AND bowlout = 'No'
           GROUP BY PlayerID, Player.Name, LeagueName, Season
           HAVING COUNT(score) >= 50
       ) AS league_avg
 WHERE Season = '2011-2012'
 GROUP BY PlayerID, Name, Season
 ORDER BY Average DESC LIMIT 0,50
;

我从未使用过 SQLite,所以如果我有一些错误的语法,请不要感到惊讶。它尝试将Average、GameCount 和LeagueName 连接成一个可以轻松按Average 排序的字符串,并且还可以使用子字符串操作轻松提取组件。

我最不确定的部分是平均值的格式。我使用了在此链接底部找到的语法。

于 2012-06-29T03:47:42.523 回答
1

正如Andriy M在评论中所发布的,有一种解决方法可以让聚合函数为不在 GROUP BY 子句中的列获得正确的结果。

由于 SQLite 规范中未定义该变通方法来解决与未来版本的兼容性问题,因此使用该变通方法是不安全的,但在这种特殊情况下它适用于我,而不会减慢查询速度,这正是我想要的。

我也不打算在未来升级我的 SQLite 版本,因为我已经计划将我的应用程序与 MySQL 数据库联机,所以我觉得发布这个答案是合理的,因为它完美地解决了我的问题。

诀窍是在字段的内部查询中使用 ORDER BY 来获取平均值。它之所以有效,是因为当外部查询尝试按 PlayerID 进行分组时,未被使用的其他列是与分组依据的字段的最后一个实例一起使用的列。因此,如果一个 PlayerID 具有三个不同的平均值,则在内部查询中,最高平均值将是最后一个,因此外部查询将使用该特定 PlayerID 的最后一个实例附带的字段。

这是代码,添加的行有注释:

SELECT  PlayerID, Name, max(score)Avg, gamesCount, LeagueName, Season
FROM( SELECT  PlayerID, Player.Name as Name, Player.Gender as Gender, ROUND(AVG(score),2) as score, COUNT(score) as gamesCount, LeagueName, Season
    FROM  Scores JOIN Players as Player USING(PlayerID)
    WHERE Score > -1 AND bowlout = 'No' AND season = '2011-2012'
    GROUP BY PlayerID, LeagueName, Season
    HAVING gamesCount >= 50
    ORDER BY score /* Here is the added line that solves it all */
) as league_avg
WHERE Gender = 'Male'
GROUP BY PlayerID
ORDER BY Avg DESC LIMIT 0,50;
于 2012-07-02T23:44:49.630 回答
0

您想通过修饰符学习WITH ROLLUP组

于 2012-06-29T01:46:06.430 回答