Я хочу иметь возможность выбрать группу строк из таблицы электронных писем и сгруппировать их по отправителю. Мой запрос выглядит так:
SELECT
`timestamp`, `fromEmail`, `subject`
FROM `incomingEmails`
GROUP BY LOWER(`fromEmail`)
ORDER BY `timestamp` DESC
Запрос почти работает так, как я хочу - он выбирает записи, сгруппированные по электронной почте. Проблема в том, что тема и временная метка не соответствуют самой последней записи для определенного адреса электронной почты.
Например, он может вернуть:
fromEmail: john@example.com, subject: hello
fromEmail: mark@example.com, subject: welcome
Когда записи в базе данных:
fromEmail: john@example.com, subject: hello
fromEmail: john@example.com, subject: programming question
fromEmail: mark@example.com, subject: welcome
Если тема "программного вопроса" самая последняя, как я могу заставить MySQL выбирать эту запись при группировании электронных писем?
источник
As of 5.7.5 ONLY_FULL_GROUP_BY is enabled by default, i.e. it's impossible to use non-aggregate columns.
Режим SQL можно изменить во время выполнения без прав администратора, поэтому отключить ONLY_FULL_GROUP_BY очень просто. Например:SET SESSION sql_mode = '';
. Демо: db-fiddle.com/f/esww483qFQXbXzJmkHZ8VT/3Вот один из подходов:
Обычно вы присоединяетесь к таблице в поисках более поздних строк. В предложении where вы указываете, что не может быть более поздних строк. Это дает вам только последнюю строку.
Если может быть несколько электронных писем с одной и той же меткой времени, этот запрос потребует уточнения. Если в таблице электронной почты есть столбец инкрементного идентификатора, измените JOIN следующим образом:
источник
textID
это неоднозначно = /LEFT JOIN
критериямAND next.timestamp <= UNIX_TIMESTAMP()
Как уже указывалось в ответе, текущий ответ неверен, потому что GROUP BY произвольно выбирает запись из окна.
Если вы используете MySQL 5.6 или MySQL 5.7 с
ONLY_FULL_GROUP_BY
, правильный (детерминированный) запрос:Для эффективного выполнения запроса требуется правильная индексация.
Обратите внимание, что для упрощения я удалил
LOWER()
, который в большинстве случаев не будет использоваться.источник
order by
подзапросе в других ответах вообще не действует.Сделайте GROUP BY после ORDER BY, заключив свой запрос в GROUP BY следующим образом:
источник
time
, самые новыеtime
или случайные?time DESC
а затем группа по берет первое (самое позднее).Согласно стандарту SQL вы не можете использовать неагрегированные столбцы в списке выбора. MySQL допускает такое использование (если не используется режим ONLY_FULL_GROUP_BY), но результат непредсказуем.
ONLY_FULL_GROUP_BY
Сначала следует выбрать fromEmail, MIN (чтение), а затем со вторым запросом (или подзапросом) - Subject.
источник
Я боролся с обоими этими подходами для более сложных запросов, чем показанные, потому что подход с подзапросом был ужасно неэффективным независимо от того, какие индексы я использовал, и потому что я не мог получить внешнее самосоединение через Hibernate.
Лучший (и самый простой) способ сделать это - сгруппировать по чему-то, что сконструировано так, чтобы содержать конкатенацию требуемых полей, а затем вытащить их, используя выражения в предложении SELECT. Если вам нужно выполнить MAX (), убедитесь, что поле, над которым вы хотите выполнить MAX (), всегда находится на самом значительном конце объединенного объекта.
Ключ к пониманию этого заключается в том, что запрос может иметь смысл только в том случае, если эти другие поля инвариантны для любого объекта, который удовлетворяет Max (), поэтому с точки зрения сортировки другие части конкатенации можно игнорировать. Он объясняет, как это сделать, в самом низу этой ссылки. http://dev.mysql.com/doc/refman/5.0/en/group-by-hidden-columns.html
Если вы можете получить событие вставки / обновления (например, триггер) для предварительного вычисления конкатенации полей, вы можете его проиндексировать, и запрос будет таким же быстрым, как если бы группа по занимала только поле, которое вы действительно хотели MAX ( ). Вы даже можете использовать его, чтобы получить максимум нескольких полей. Я использую его для выполнения запросов к многомерным деревьям, выраженным в виде вложенных наборов.
источник