MySQL Выбор деталей с использованием max - PullRequest
3 голосов
/ 03 декабря 2011

У меня есть набор таблиц MySQL, содержащих информацию из футбольной игры.

Таблицы:

  • Players - playerID (PK), playerName
  • Совпадения - matchID (PK), matchSeason, matchRound, matchType
  • PlayersMatch - playerID, matchID (comp PK), matchRating, playerForm, playerAge, позиция (может быть нулевой)

Данные, хранящиеся в этих таблицах, связаны с игрой игрока. Игрок играет в матче и имеет оценку производительности (matchRating). В PlayersMatch есть запись для каждого матча, в котором участвует игрок, запись текущей формы игроков, производительности матча, их возраста на момент матча (для исторических целей) и позиции, в которой они играли.

Теперь, в настоящее время, я использую следующий запрос, чтобы составить список 10 лучших игроков за весь сезон (лучшая производительность в сезоне, в отличие от лучшей производительности за раунд):

SELECT playerID, matchID, playerForm, playerAge, MAX(matchRating)
FROM PlayersMatch
INNER JOIN Matches ON PlayersMatch.matchID = Matches.matchID
WHERE Matches.matchSeason = 35
AND Matches.matchType = 'L'
AND PlayersMatch.position IS NOT NULL
GROUP BY PlayersMatch.playerID
ORDER BY MAX(matchRating) DESC, playerForm ASC

Проблема, которую я получаю, заключается в том, что, в то время как я получаю правильный ID игрока и MatchRating игрока, я получаю неправильный MatchID, форму, возраст и другую информацию (т.е. они из других записей).

Я попытался добавить matchID в группу, и, хотя я получил правильную информацию, у меня были дубликаты, поскольку он создавал дубликаты записей для игроков (потому что playerID и matchID составляют PK в PlayersMatch).

Ваша помощь в этом очень ценится.

Редактировать: После некоторого прочтения я должен написать SQL неправильно, и что группа по будет возвращать правильную информацию, только если у меня только playerID и max (matchRating) - на самом по крайней мере, чтобы быть ANSI SQL правильно.

В таком случае, как мне получить информацию о соответствующем совпадении для этого выступления, если я использую max / group by?

Редактировать 2: Похоже, у меня есть рабочий запрос:

SELECT * FROM PlayersMatch
INNER JOIN 
   (SELECT playerID, MAX(matchRating)
    FROM PlayersMatch p2
    JOIN Matches
      ON p2.matchID = Matches.matchID
    WHERE matchSeason = 35
    AND matchType = 'L'
    AND p2.position IS NOT NULL
    GROUP BY p2.playerID) AS p1
  ON PlayersMatch.playerID = p1.playerID
  AND PlayersMatch.matchRating = p1.matchRating
JOIN Matches m2
  ON PlayersMatch.matchID = m2.matchID
WHERE m2.matchSeason = 35
AND m2.matchType = 'L'
AND PlayersMatch.position IS NOT NULL
ORDER BY matchRating DESC

Единственная проблема сейчас заключается в том, что для запуска требуется 21 секунда. Этот запрос выглядит правильно?

Ответы [ 2 ]

1 голос
/ 04 декабря 2011

Добавьте второй индекс PlayersMatch на основе MatchID только для вашего предварительного квалификационного присоединения к матчам.Добавьте индекс в таблицу соответствий для matchSeason и введите.

Из ваших отредактированных и опубликованных образцов данных я думаю, что это решает получение первого "соответствия", которое квалифицирует составные множественные экземпляры под одним и тем же "рангом".Итак, опять же, самый внутренний получает лучший MatchRating, так как ваш "MAX ()", очевидно, ищет самый высокий рейтинг.После этого он немедленно присоединится к матчам игроков и получит ПЕРВЫЙ идентификатор матча для этого человека с таким же рейтингом.Наконец, чтобы закрыть его, мы можем напрямую присоединиться к человеку для получения информации об имени и к совпадению на основе первого найденного идентификатора совпадения, поэтому дубликаты не должны возвращаться ... Этот окончательный результат сортируется по рейтингу совпадения.

SELECT STRAIGHT_JOIN
      Players.PlayerName,
      M2.*,
      PM.MatchRating,
      PM.PlayerForm,
      PM.PlayerAge,
      PM.Position
   FROM 
      ( select PreMatch.PlayerID,
               PreMatch.MaxMatch,
               MIN( P3.MatchID ) as FirstMatch
           FROM
               ( SELECT 
                    p2.playerID, 
                    MAX(p2.matchRating) MaxMatch
                 FROM 
                    Matches
                       JOIN PlayersMatch P2
                          ON Matches.MatchID = p2.matchID
                         AND P2.Position is not null
                 WHERE 
                        Matches.MatchSeason = 35
                    AND Matches.MatchType = 'L'
                 GROUP BY
                    p2.playerID ) PreMatch

               JOIN PlayersMatch P3
                   ON PreMatch.PlayerID = P3.PlayerID
                  AND PreMatch.MaxMatch = P3.MatchRating
                  AND P3.Position is not null

                  JOIN Matches M2
                     on P3.MatchID = M2.MatchID
                    AND M2.MatchSeason = 35
                    AND M2.MatchType = 'L' 
          GROUP BY
             PreMatch.PlayerID,
             PreMatch.MaxMatch
      ) AS p1

      JOIN Players
         on P1.PlayerID = Players.PlayerID

      JOIN PlayersMatch PM
          on p1.FirstMatch = PM.MatchID 

   ORDER BY 
      p1.MaxMatch DESC
0 голосов
/ 03 декабря 2011

Агрегат работает только для фактического столбца, к которому он применяется. Это не основано на записях. Он выбирает максимальное значение для рейтинга, но не определяет, как агрегируются другие столбцы.

Итак, когда у вас есть записи:

player 1 | match 1 | 10 
player 1 | match 2 | 5

и вы группируете их по игроку, ему нужно выбрать только одно значение для поля 'match', но какое не определено: оно не зависит от агрегатов в других столбцах.

Для того, что вы хотите сделать, вам нужен подзапрос:

SELECT p1.playerID, p1.matchID, p1.playerAge, MAX(p1.matchRating)
FROM PlayersMatch P1
JOIN PlayersMatch p2 on p1.id = 
   (SELECT id 
    FROM PlayerMatch p2 
    WHERE p2.playerId = p1.playerId 
    ORDER BY MAX(p2.matchRating) DESC 
    LIMIT 1)
GROUP BY playerID

Обратите внимание, что я ввел сгенерированный первичный ключ для таблицы соответствия игроков (поскольку я не уверен в синтаксисе соединения для составных ключей и общих однополевых искусственных ключей общего назначения.) У вас все еще может быть уникальное ограничение вкл (playerID, matchId).

...