Подтвердить что ты не робот

Получить последний отчетливый набор записей

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

id   code   value   datetime   timestamp

В этой таблице единственные уникальные значения находятся в id, то есть в первичном ключе.

Я хочу получить последний отчетный набор записей в этой таблице на основе значения datetime. Например, скажем ниже, моя таблица

id   code   value   datetime               timestamp
1    1023   23.56   2011-04-05 14:54:52    1234223421
2    1024   23.56   2011-04-05 14:55:52    1234223423
3    1025   23.56   2011-04-05 14:56:52    1234223424
4    1023   23.56   2011-04-05 14:57:52    1234223425
5    1025   23.56   2011-04-05 14:58:52    1234223426
6    1025   23.56   2011-04-05 14:59:52    1234223427
7    1024   23.56   2011-04-05 15:00:12    1234223428
8    1026   23.56   2011-04-05 15:01:14    1234223429
9    1025   23.56   2011-04-05 15:02:22    1234223430

Я хочу получить записи с идентификаторами 4, 7, 8 и 9, т.е. последний набор записей с разными кодами (на основе значения datetime). То, что я выделил, является просто примером того, чего я пытаюсь достичь, поскольку эта таблица в конечном итоге будет содержать миллионы записей и сотни отдельных значений кода.

Какой SQL-оператор можно использовать для достижения этого? Кажется, я не могу сделать это с помощью одного оператора SQL. Моя база данных - это MySQL 5.

4b9b3361

Ответ 1

Это должно сработать для вас.

 SELECT * 
 FROM [tableName] 
 WHERE id IN (SELECT MAX(id) FROM [tableName] GROUP BY code)

Если id является AUTO_INCREMENT, нет необходимости беспокоиться о времени, которое намного дороже для вычисления, так как последнее время datetime также будет иметь самый высокий идентификатор.

Обновление:. С точки зрения производительности убедитесь, что столбцы id и code индексируются при работе с большим количеством записей. Если id является основным ключом, он встроен, но вам может потребоваться добавить некластеризованный индекс, охватывающий code и id.

Ответ 2

Попробуйте следующее:

SELECT * 
  FROM <YOUR_TABLE>
 WHERE (code, datetime, timestamp) IN
 (
   SELECT code, MAX(datetime), MAX(timestamp)
     FROM <YOUR_TABLE>
    GROUP BY code
 )

Ответ 3

Это и старое сообщение, но тестирование @smdrager на большие таблицы было очень медленным. Мое исправить это было использование "внутреннего соединения" вместо "где в".

SELECT * 
 FROM [tableName] as t1
 INNER JOIN (SELECT MAX(id) as id FROM [tableName] GROUP BY code) as t2
 ON t1.id = t2.id

Это работало очень быстро.

Ответ 4

Я попробую что-то вроде этого:

select * from table
where id in (
    select id
    from table
    group by code
    having datetime = max(datetime)
)

(отказ от ответственности: это не проверено)

Если строка с большим значением datetime также имеет больший id, решение, предлагаемое smdrager, выполняется быстрее.

Ответ 5

Похоже, что все существующие ответы предлагают сделать GROUP BY code на всю таблицу. Когда это логически корректно, в действительности этот запрос будет проходить через всю (!) Таблицу (чтобы убедиться, используйте EXPLAIN). В моем случае у меня в таблице менее 500 тыс. Строк и выполняется ...GROUP BY code занимает 0,3 секунды, что абсолютно недопустимо.

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

  • Мне нужно выбрать только топ-20 записей
  • Количество записей с одинаковым кодом в последних X записях относительно невелико
  • Общее количество записей >> количество доступного code >> количество "лучших" записей, которые вы хотите получить

Экспериментируя с числами, я обнаружил, что всегда могу найти 20 разных code если выберу только последние 50 записей. И в этом случае работает следующий запрос (имея в виду комментарий @smdrager о высокой вероятности использования id вместо datetime)

SELECT id, code
FROM tablename
ORDER BY id DESC 
LIMIT 50

Выбор только последних 50 записей очень быстр, потому что не нужно проверять всю таблицу. А остальное - выбрать топ-20 с отличным code из этих 50 записей.

Очевидно, что запросы для набора из 50 (100, 500) элементов выполняются значительно быстрее, чем для всей таблицы с сотнями тысяч записей.

Необработанный SQL "Постобработка"

SELECT MAX(id) as id, code FROM 
    (SELECT id, code
     FROM tablename
     ORDER BY id DESC 
     LIMIT 50) AS nested 
GROUP BY code
ORDER BY id DESC 
LIMIT 20

Бэкэнд-сторона "Постобработка"

И после этого вам нужно обработать данные на вашем языке программирования, чтобы включить в окончательный набор только записи с отдельным code.

Какой-то псевдокод Python:

records = select_simple_top_records(50)
added_codes = []
top_records = []
for record in records:
    # If record for this code was already found before
    # Note: this is not optimal, better to use structure allowing O(1) search and insert
    if record['code'] in added_codes:
        continue
    # Save record
    top_records.append(record)
    added_codes.append(record['code'])
    # If we found all top-20 required, finish
    if len(top_records) >= 20:
        break