Возврат соответствующих столбцов функции MAX в MySQL - PullRequest
4 голосов
/ 19 июня 2011

У меня есть таблица, которая содержит результаты, набранные игроками в боулинг-центре.В каждом ряду есть данные о том, какой игрок играл в игру, в какой лиге он играл, дату, счет в отдельной игре, номер лэйна и т. Д.

Я пытаюсь получитькто играл (и в какой лиге и в какую дату ... в основном весь ряд) лучшая серия (по три игры) на каждой дорожке.

То, что у меня пока есть, это

SELECT PlayerID, LaneNumber, MAX(Series)
  FROM (SELECT Season, LeagueName, LaneNumber, WeekNumber, PlayerID, Date, SUM(Score) AS Series 
          FROM Scores
      GROUP BY Season, LeagueName, WeekNumber, PlayerID)
GROUP BY LaneNumber

Это работает, так как я получаю три лучшие игры для каждой отдельной дорожки, что на самом деле то, что я хочу, но другое поле, содержащее PlayerID, на самом деле не корректно.

В моей таблице самая лучшаясчет на 24-й дорожке (полученный из SUM (Score) и GROUP BY Season, LeagueName, WeekNumber, PlayerID) равен 848, и его сыграл игрок с PlayerID 36.

Вместо этого я получаю Lane 24с 848 (что правильно), но PlayedID возвращается 3166. То же самое происходит на каждой отдельной дорожке.(Например, я получаю идентификаторы игроков, которые явно неверны. И если у меня были другие столбцы в первом выборе, они также неверны)

Ответы [ 4 ]

3 голосов
/ 19 июня 2011

Вы нарушаете семантику GROUP BY.

При использовании GROUP BY имеет смысл только SELECT столбцы, которые вы сгруппировали (например, LaneNumber), и агрегатные функции другихстолбцы (например, MAX(Series)).Не имеет смысла выбирать что-либо еще (в вашем случае, PlayerID), потому что вы не указываете , какой ID игрока вы хотите среди тех, у кого одинаковые LaneNumber.

К сожалению, MySql по умолчанию позволит вам сделать это без сообщения об ошибке и вернет любое значение, выбранное для ошибочного столбца.В вашем случае это означает, что вы возвращаете идентификатор игрока, «случайно» выбранный среди тех, которые включены в указанную группу.

Вы также делаете это во внутреннем запросе, где вы выбираете LaneNumber,WeekNumber и Date.

Решение

Запрос необходимо переписать, но сначала необходимо тщательно указать, какие именно результаты вы хотите получить.Вы хотите лучшего игрока и соответствующие данные для каждой серии (и любой дорожки)?Для каждой серии и полосы отдельно?Ответ на этот вопрос будет определять, что вам нужно GROUP BY, и, соответственно, как будет выглядеть запрос.

2 голосов
/ 19 июня 2011

Как отмечает @Jon, вам необходимо удалить те элементы, которые НЕ применимы к конкретному человеку.Затем, поскольку у @Ord был самый близкий образец, было бы лучше предварительно запросить результаты в отдельной таблице (не временной, поскольку MySQL захлебнется, пытаясь запросить себя при самосоединении во втором запросе).

Итак, для меня (я был боулером лиги несколько лет назад) и ваш контент, охватывающий ВСЕ лиги, никогда не будет двух разных лиг на одной линии в одно и то же время в течение всего вечера, однакоу вас могут быть разные лиги, начинающиеся в разное время ... 6-8: 30, 8: 45-11, например ... так что группировка по лиге и дате будет работать.Однако вам НУЖНО, чтобы игрок как часть группы получил соответствующие значения SUM ().

Чтобы уточнить ответы, предположим, что у меня есть следующие данные.Эти данные будут представлять только одну линию, одну неделю, один сезон, но две лиги и 3 игрока в каждой лиге (с единственной целью показать результаты и ограничить содержание здесь)

League   Player   Score
L1       1        223
L1       1        218
L1       1        204
L1       2        187
L1       2        201
L1       2        189
L1       3        148
L1       3        152
L1       3        158

L2       4        189
L2       4        195
L2       4        192
L2       5        182
L2       5        199
L2       5        209
L2       6        228
L2       6        234
L2       6        218


CREATE TABLE SeriesScores2
SELECT 
      Season, 
      LeagueName, 
      LaneNumber, 
      WeekNumber, 
      PlayerID, 
      SUM(Score) AS Series 
   FROM 
      Scores
   GROUP BY 
      Season, 
      LeagueName, 
      LaneNumber, 
      WeekNumber, 
      PlayerID;

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

Season   League   Lane   Week   Player   Series
1        L1       1      1      1        645
1        L1       1      1      2        577
1        L1       1      1      3        458
1        L2       1      1      4        576
1        L2       1      1      5        590
1        L2       1      1      6        680

Это дает нам предвестник для определенияmax (), в противном случае нам пришлось бы дублировать запрос внутри себя и на внешнем уровне, что усложняет его, чем предварительная агрегация.

Теперь указанная выше постоянная таблица (может быть удалена ПОСЛЕ получения результатов)запросите ПЕРВЫЙ (PreQuery) максимальный балл за ЛИГУ на ЛЮБОЙ ... Например: как правило, у мужской лиги, как правило, более высокие результаты в серии, чем у женщин ... схожие с разными возрастными группами.Итак, наивысшая оценка мужской лиги Lane 1 и женской лиги Lane 1 наивысшая оценка и т. Д. Наибольшая оценка, как правило, определяется одной неделей из всего сезона, а не самой высокой серией на линию каждую неделю.

Теперь, PreQueryПсевдоним "ss" относится только к сезону, лиге, лэйну и максимальным сериям.Как только это станет известно, самостоятельно присоединитесь к серии баллов, чтобы набрать ВОЗ DID этот самый высокий балл на указанной полосе и выяснить, кто и на какой неделе это произошло

select
      ss.season, 
      ss.leaguename, 
      ss.lanenumber, 
      ss.highestSeries, 
      ss2.PlayerID, 
      ss2.WeekNumber
   from
      ( select season, leaguename, lanenumber, max( series ) highestSeries
           from SeriesScores2
           group by season, leaguename, lanenumber ) ss
      join SeriesScores2 ss2
         on ss.Season = ss2.Season
        and ss.LeagueName = ss2.LeagueName
        and ss.LaneNumber = ss2.LaneNumber
        and ss.HighestSeries = ss2.Series

Теперь из приведенного выше запроса ...давайте разберемся с этим.Если мы возьмем внутренний запрос "ss"

  ( select season, leaguename, lanenumber, max( series ) highestSeries
       from SeriesScores2
       group by season, leaguename, lanenumber ) ss

, мы получим самые высокие оценки по лиге (например: мужская лига против женской лиги на той же неделе, в ту же ночь, на той же линии, и мы находим (ниже),просто по максимуму, но у вас нет ВОЗ или какой недели, только самые высокие серии были выбиты вне зависимости от недели или человека. Таким образом, ЭТО становится основой ПРИСОЕДИНЕНИЯ к предварительно агрегированной таблице «SeriesScores2», но здесь мы имеемнаивысший балл серии, чтобы убедиться, что мы нашли правильного человека

Season  League   Lane   HighestSeries
1       L1       1      645
1       L2       1      680

To refresh preaggregation
Season   League   Lane   Week   Player   Series
1        L1       1      1      1        645    <-- Join finds THIS entry League 1
1        L1       1      1      2        577
1        L1       1      1      3        458
1        L2       1      1      4        576
1        L2       1      1      5        590
1        L2       1      1      6        680    <-- Join finds THIS entry League 2

Итак, мои оригинальные запросы работали так, как я их проверял перед публикацией. Я не знаю, какой у вас сбой, если только имя столбца не верноеили что-то в этом роде. Что касается столбца «Дата», мне было все равно, потому что у вас был номер недели, который соответствовал бы неделе боулинга и в любом случае имел бы отношение 1: 1 к дате. Столбец датыможно было бы добавить к предварительной агрегации SeriesScores2 и использовать при получении идентификатора человека и недели.Несколько ночей на той же неделе, ТОГДА вам понадобится точная дата).

Надеюсь, это прояснит ваши вопросы / комментарии.

2 голосов
/ 19 июня 2011

Посмотрите здесь: http://dev.mysql.com/doc/refman/5.0/en/example-maximum-column-group-row.html

Возможно, вам будет сложно сделать все это одним запросом, но в основном вы хотите сгенерировать данные ряда, как вы это делали:

SELECT Season, LeagueName, LaneNumber, WeekNumber, PlayerID, Date, SUM(Score) AS Series 
      FROM Scores
  GROUP BY Season, LeagueName, WeekNumber, PlayerID

Затем, вместо получения значений максимальной серии из этой таблицы, вы захотите добавить предложение: WHERE Series=, а затем, чтобы получить правильное значение, вам нужно сделать еще один выбор, где вы получите максимум (Series), где LaneNumber равното же самое в обеих таблицах.Я бы написал это для вас, но я недостаточно уверен в своих возможностях MySQL!

1 голос
/ 19 июня 2011

Хорошо, я пытался написать код MySQL, о котором я думал (я не смог устоять ...):

CREATE TEMPORARY TABLE SeriesScores
SELECT Season, LeagueName, LaneNumber, WeekNumber, PlayerID, SUM(Score) AS Series 
    FROM Scores
    GROUP BY Season, LeagueName, WeekNumber, PlayerID;

Этот бит просто получает оценки для каждой серии, как вы указали в своем собственном коде MySQL. Разница лишь в том, что я не выбираю Date, потому что, поскольку мы не группируем его, его значение будет случайным. Тогда:

SELECT PlayerID, LaneNumber, Series
    FROM SeriesScores s1
    WHERE  Series=(SELECT MAX(s2.Series)
          FROM SeriesScores s2
          WHERE s1.LaneNumber = s2.LaneNumber);

Этот бит просто выбирает то, что вам нужно из SeriesScores, и учитывает только те строки, где оценка серии является максимальной для этой полосы.

Это работает для вас?

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...