2012-06-29 35 views
2

我有一個查詢用於保齡球中心以降序排列所有最佳平均值。獲取由另一列分組的多個AVG的MAX

除了如果一名球員參加兩個不同的聯賽(或者因爲每個賽季之後的平均值重置,我不按季節分組),一切都很好,我只想要自給我以來的最佳平均水平不想重複。 (同一玩家在不同聯賽中的平均數不會累積,所以玩家可以擁有多於一個的平均數)

我以爲在Stack Overflow問(here)之後,我剛剛解決了這個問題,但最近,有人告訴我,有時候,查詢存在一些問題,我不知道我以前沒有注意到。

問題是,即使我沒有重複的名字,並且我得到了正確的MAX平均值,但其他列(如leagueName,玩過的遊戲數量和季節並不總是正確的,如果玩家在多個聯賽中踢球。這裏的查詢:

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,但其他領域,如leagueName如果有多個聯賽一個球員進入,從他參加的聯賽中隨機選擇。

我想要的是獲得與球員和他的最高平均值相對應的聯賽名稱(和所有其他信息)。

下面是一個例子:

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 

正如你所看到的,史密斯,亞當正確的AVG,但與Name/Avg組合關聯的錯誤聯盟。

我嘗試將外部GROUP BY子句更改爲PlayerID,LeagueName,Season,但每個賽季每個聯盟只重新分配一次,然後再次獲取重複項。除了僅僅使用Java應用程序之外,我不知道要再試一次,抓取所有結果並刪除Java中的重複項。顯然,我寧願從SQL查詢中第一次得到正確的結果。

作爲一個旁註,即使它在本文前面提到過,有時查詢不會有「AND season ='2011-2012'」部分,所以我不能得到不同的同一個玩家的重複無論是季節。

編輯:我使用SQLite的情況下,有些人沒有注意到標籤。

+1

有是證明我很有限的測試工作的解決方案。它依賴於經驗性建立的東西,而且沒有正式記錄。 (我甚至不確定我是否可以說「已建立」,因爲我的測試太有限了,但是,我的結果在整個測試中都是一致的)。我認爲這種解決方案不值得通過發佈作爲答案來宣傳。如果您有興趣,可以在[SQL小提琴](http://sqlfiddle.com/#!5/5d339/3)上找到示例查詢。 –

+0

@AndriyM - 有趣而可信的「解決方案」。但我理解你的關心。即使它可以與這個版本一起工作,SQLite的後續版本的可靠性如何?我同意這可能不是一個明智的選擇。 – dbenham

+0

@AndriyM謝謝,它完美的作品!你應該發佈這個答案。我知道它可能不適用於未來的SQLite實現,但對於這種特殊情況,它將起作用。下一個版本將使用MySQL基於Web,所以我知道我不會升級SQLite。非常感謝,讓這個答案,我會標記爲接受。 –

回答

1

由於Andriy M在註釋中發佈,因此有一種解決方法可讓聚合函數爲不在GROUP BY子句中的列獲取正確結果。

因爲未在SQLite規範中定義兼容性問題,所以使用該解決方法並不安全,但它在這種特殊情況下適用於我,而不會減慢查詢的速度,這正是我想要的。

我不打算在未來升級我的SQLite版本,因爲我已經有計劃將我的應用程序與MySQL數據庫聯機,所以我覺得發佈這個答案是合理的,因爲它完美地解決了我的問題。

訣竅是在平均值字段的內部查詢中使用ORDER BY。它的工作原理是因爲當外部查詢嘗試使用GROUP 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; 
0

你想通過修改

+0

因爲我使用SQLite它不起作用,謝謝。我會編輯我的問題,但它已經在標籤 –

2

學習WITH ROLLUP組,我相信這樣的事情應該工作。

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排序,並且還可以使用子字符串操作輕鬆提取組件。

我最不確定的部分是平均格式。我用我發現的語法at the bottom of this link

+0

好主意!到目前爲止,唯一真正能夠發現的問題是使用'gamesCount'名稱。它實際上不是一個列。在OP的查詢中,它是一個分配給「COUNT(分數)」的別名(顯然,SQLite允許你的'HAVING'子句通過別名引用列)。所以看起來(我不是105%肯定)你只需要用'COUNT(score)> = 50'來代替'gamesCount> = 50',或者將'COUNT(score)AS gamesCount'列添加到子-SELECT列表。 –

+0

@AndriyM是對的,雙向工作。如果我沒有找到運行得更快的答案,我會將您的答案標記爲已接受,因爲即使它有效,此查詢速度也非常慢,我不知道應該使用索引來改進它。謝謝你的工作和巧妙的解決方案 –

+0

@AndriyM - 是的,我錯過了。謝謝。我編輯了答案。 – dbenham