Как группировать по заказу DESC - программирование
Подтвердить что ты не робот

Как группировать по заказу DESC

У меня есть следующая таблица, называемая вопросами:

ID | asker 
1  | Bob
2  | Bob
3  | Marley

Я хочу, чтобы каждый выборчик выбирал только один раз, и если есть несколько запросов с тем же именем, выберите один из самых высоких идентификаторов. Итак, ожидаемые результаты:

ID | asker 
3  | Marley
2  | Bob

Я использую следующий запрос:

SELECT * FROM questions GROUP by questions.asker ORDER by questions.id DESC

Получаю следующий результат:

ID | asker 
3  | Marley
1  | Bob

Таким образом, он выбирает первый "Боб", с которым он сталкивается, вместо последнего.

Спасибо

4b9b3361

Ответ 1

Если вам нужен последний id для каждого asker, вам следует использовать функцию агрегирования:

SELECT max(id) as id, 
   asker
FROM questions 
GROUP by asker 
ORDER by id DESC

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

Из документов MySQL:

MySQL расширяет использование GROUP BY, так что список выбора может ссылаться на неагрегированные столбцы, не указанные в предложении GROUP BY.... Вы можете использовать эту функцию для повышения производительности, избегая ненужной сортировки и группировки столбцов. Однако это полезно, прежде всего, когда все значения в каждом неагрегированном столбце, не названном в GROUP BY, одинаковы для каждой группы. Сервер может свободно выбирать любое значение из каждой группы, поэтому, если они не совпадают, выбранные значения являются неопределенными. Кроме того, на выбор значений из каждой группы нельзя повлиять, добавив предложение ORDER BY. Сортировка набора результатов происходит после выбора значений, и ORDER BY не влияет на то, какие значения выбирает сервер.

Теперь, если у вас есть другие столбцы, которые нужно вернуть из таблицы, но вы не хотите добавлять их в GROUP BY из-за противоречивых результатов, которые вы можете получить, то вы можете использовать для этого подзапрос. (Демо)

select 
  q.Id,
  q.asker,
  q.other -- add other columns here
from questions q
inner join
(
  -- get your values from the group by
  SELECT max(id) as id, 
    asker
  FROM questions 
  GROUP by asker 
) m
  on q.id = m.id
order by q.id desc

Ответ 2

Обычно MySQL позволяет группировать только записи по возрастанию. Поэтому мы можем заказать записи перед группировкой.

SELECT *
FROM (
  SELECT *
  FROM questions
  ORDER BY id DESC
) AS questions
GROUP BY questions.asker

Ответ 3

Записи должны быть сгруппированы с помощью GROUP BY и MAX(), чтобы получить максимальный идентификатор для каждого asker.

SELECT  asker, MAX(ID) ID
FROM    TableName
GROUP   BY asker

ВЫХОД

╔════════╦════╗
║ ASKER  ║ ID ║
╠════════╬════╣
║ Bob    ║  2 ║
║ Marley ║  3 ║
╚════════╩════╝

Ответ 4

Другие верны в использовании MAX (ID) для получения желаемых результатов. Если вам интересно, почему ваш запрос не работает, потому что ORDER BY происходит после GROUP BY.

Ответ 5

Чтобы получить каждый столбец:

SELECT * FROM questions
WHERE id IN 
(SELECT max(id) as id, asker
FROM questions 
GROUP by asker 
ORDER by id DESC)

Улучшена версия ответа @bluefeet.

Ответ 6

Это потому, что ORDER BY выполняется ПОСЛЕ GROUP BY.

Попробуй это:

SELECT * FROM questions
WHERE id IN 
(
    SELECT max(id) as id
    FROM questions 
    GROUP by asker 
    ORDER by id DESC
)

Ответ 7

Я пишу этот ответ, потому что первая альтернатива @Taryn в принятом ответе работает, только если вы точно выбираете только столбцы, используемые в GROUP BY и MAX. Пользователь задает вопрос, выбирая все столбцы в таблице (он использовал SELECT *). Поэтому, когда вы добавляете в таблицу еще 3-й столбец, значение этого столбца в результате запроса будет неверным. Вы получите смешанные значения из разных строк таблицы. Вторая/более длинная альтернатива @Taryn (с использованием внутреннего соединения и подзапроса) работает, но запрос бесполезно сложен и в моем случае использования в 5 раз медленнее, чем моя простая альтернатива ниже.


Рассмотрим questions таблицы:

id | asker 
-----------
1  | Bob
2  | Bob
3  | Marley

Запрос SELECT max(id) as id, asker FROM questions GROUP BY asker ORDER BY id DESC возвращает ожидаемое:

id | asker 
-----------
3  | Marley
2  | Bob

Теперь рассмотрим еще одну таблицу questions:

id | asker  | other
-------------------
1  | Bob    | 1st
2  | Bob    | 2nd
3  | Marley | 3rd

Запрос SELECT max(id) as id, asker, other FROM questions GROUP BY asker ORDER BY id DESC возвращает неожиданное:

id | asker  | other
-------------------
3  | Marley | 3rd
2  | Bob    | 1st

... обратите внимание, что значение other для второй строки результата неверно, поскольку id=2 поступает из второй строки таблицы, а other=1st - из первой строки таблицы! Таким образом, многие пользователи в комментариях Тарына сообщают, что это решение не работает.


Возможное простое решение при выборе еще одного столбца - использовать GROUP BY + DESC:

SELECT id, asker, other FROM questions GROUP BY asker DESC

id | asker  | other
-------------------
3  | Marley | 3rd
2  | Bob    | 2nd

(см. демонстрацию: https://www.db-fiddle.com/f/esww483qFQXbXzJmkHZ8VT/10)

... но это простое решение имеет некоторые ограничения:

  • Таблица должна быть InnoDB (я думаю, что это не проблема, потому что вы получите лучшую производительность, а также, поскольку MySQL> = 5.5.5 по умолчанию/предпочтительный механизм хранения был изменен с MyISAM на InnoDB)
  • Вы должны создать индекс для столбца, который используется в GROUP BY - поэтому asker в этом случае (я думаю, что это не проблема, потому что вы получите лучшую производительность, так как индекс подходит в этом случае. GROUP BY обычно требует создания таблицы tmp, но когда индекс доступен tmp таблица не будет создана, что быстрее)
  • Для MySQL 5.7 и 8.0 необходимо отключить режим SQL ONLY_FULL_GROUP_BY (например, SET SESSION sql_mode = '';) или использовать ANY_VALUE() для выбранных столбцов, которые не агрегированы, чтобы избежать ошибки ER_WRONG_FIELD_WITH_GROUP.
  • К сожалению, разработчики MySQL прекратили поддержку ASC/DESC с помощью GROUP BY, начиная с MySQL 8.0 https://dev.mysql.com/worklog/task/?id=8693, но, к счастью, есть альтернатива GROUP BY col1 ORDER BY col1 ASC/DESC:

SELECT id, asker, other FROM questions GROUP BY asker ORDER BY asker DESC

id | asker  | other
-------------------
3  | Marley | 3rd
2  | Bob    | 2nd

(см. демонстрацию: https://www.db-fiddle.com/f/esww483qFQXbXzJmkHZ8VT/11)

... результат такой же, как и выше для GROUP BY... DESC (не забудьте использовать InnoDB и создать индекс).