2

ボウリング センターで、すべての最高の平均値を降順で並べ替えるために使用されるクエリがあります。

プレーヤーが2つの異なるリーグでプレーする場合(または、各シーズンの後に平均がリセットされるため、シーズンごとにグループ化しない場合)を除いて、すべてがうまく機能します。 . (同じプレーヤーの異なるリーグでの平均は累積されないため、1 人のプレーヤーが複数の平均を持つことができます)

少し前に Stack Overflow で質問したところ、その問題は解決したと思っていましたが (こちら)、最近、クエリに問題があることがあると言われました。

問題は、重複した名前を取得せず、正しい 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

ご覧のとおり、Smith、Adam は正しい AVG を持っていますが、Name/Avg コンボに関連付けられたリーグは間違っています。

外部の GROUP BY 句を PlayerID、LeagueName、Season に変更しようとしましたが、シーズンごとにリーグごとに再分離され、重複が再び返されます。これが含まれているJavaアプリケーションを使用して、すべての結果を取得し、Javaで重複を削除する以外に、何を試すべきかわかりません。明らかに、私は SQL クエリから初めて正しい結果を得たいと思っています。

補足として、この投稿の前半で言及されていましたが、クエリに「AND シーズン = '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 で簡単にソートできる 1 つの文字列に連結し、部分文字列操作を使用してコンポーネントを簡単に抽出しようとします。

私が最も確信が持てない部分は、平均のフォーマットです。このリンクの下部にある構文を使用しました。

于 2012-06-29T03:47:42.523 に答える
1

コメントでAndriy Mが投稿したように、集計関数が GROUP BY 句に含まれていない列に対して正しい結果を取得できるようにするための回避策があります。

SQLite仕様で定義されていないため、将来のバージョンとの互換性の問題にその回避策を使用することは安全ではありませんが、この特定のケースでは、クエリを遅くすることなく機能します。これはまさに私が望んでいたことです.

代わりにMySQLデータベースを使用してアプリケーションをオンラインにする計画がすでにあるため、今後SQLiteバージョンをアップグレードする予定はありません.

トリックは、平均のフィールドの内部クエリで ORDER BY を使用することです。外部クエリが GROUP BY PlayerID を試行すると、グループ化されていない他の列が使用されるため、グループ化されたフィールドの最後のインスタンスに移動するため、機能します。そのため、PlayerID に 3 つの異なる平均がある場合、内部クエリでは最も高い平均が最後になるため、外部クエリはその特定の 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 に答える