Как выбрать строки с меткой времени текущего дня?

105

Я пытаюсь выбрать только сегодняшние записи из таблицы базы данных.

В настоящее время я использую

SELECT * FROM `table` WHERE (`timestamp` > DATE_SUB(now(), INTERVAL 1 DAY));

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

Джеки Хонсон
источник

Ответы:

193

использовать DATEиCURDATE()

SELECT * FROM `table` WHERE DATE(`timestamp`) = CURDATE()

Я предполагаю, что использование по- DATE прежнему использует INDEX .

посмотреть план выполнения на ДЕМО

Джон Ву
источник
Посмотрите разницу: SQL-Fiddle Обратите внимание на FILTERED = 25 во втором запросе.
ypercubeᵀᴹ
@ypercube о, я пропустил это, но мне было интересно, почему стоимость на дополнительных Using where; Using index?
Джон Ву
1
Индекс используется для выбора строк. Но весь индекс сканируется (и все значения преобразуются с помощью DATE () для оценки условия) с вашим запросом. Я дополню свой ответ лучшим примером.
ypercubeᵀᴹ
1
при всем уважении, решение ypercube лучше по соображениям производительности, если в вашей таблице сотни тысяч строк, вам обязательно стоит пойти в этом направлении
Винсент
1
`` важны, потому что timestampdateкак в моем случае) это зарезервированное слово MySQL
Виктор Феррейра,
58

Если вы хотите, чтобы использовался индекс, а запрос не сканировал таблицу:

WHERE timestamp >= CURDATE()
  AND timestamp < CURDATE() + INTERVAL 1 DAY

Чтобы показать, как это влияет на фактические планы выполнения, мы протестируем SQL-Fiddle (чрезвычайно полезный сайт):

CREATE TABLE test                            --- simple table
    ( id INT NOT NULL AUTO_INCREMENT
    ,`timestamp` datetime                    --- index timestamp
    , data VARCHAR(100) NOT NULL 
          DEFAULT 'Sample data'
    , PRIMARY KEY (id)
    , INDEX t_IX (`timestamp`, id)
    ) ;

INSERT INTO test
    (`timestamp`)
VALUES
    ('2013-02-08 00:01:12'),
    ---                                      --- insert about 7k rows
    ('2013-02-08 20:01:12') ;

Давайте попробуем сейчас две версии.


Версия 1 с DATE(timestamp) = ?

EXPLAIN
SELECT * FROM test 
WHERE DATE(timestamp) = CURDATE()            ---  using DATE(timestamp)
ORDER BY timestamp ;

Объясните:

ID  SELECT_TYPE  TABLE  TYPE  POSSIBLE_KEYS  KEY  KEY_LEN  REF 
1   SIMPLE       test   ALL

ROWS  FILTERED  EXTRA
6671  100       Using where; Using filesort

Он фильтрует все (6671) строки, а затем выполняет сортировку файлов (это не проблема, поскольку возвращаемых строк мало)


Версия 2 с timestamp <= ? AND timestamp < ?

EXPLAIN
SELECT * FROM test 
WHERE timestamp >= CURDATE()
  AND timestamp < CURDATE() + INTERVAL 1 DAY
ORDER BY timestamp ;

Объясните:

ID  SELECT_TYPE  TABLE  TYPE  POSSIBLE_KEYS  KEY  KEY_LEN  REF 
1   SIMPLE       test   range t_IX           t_IX    9 

ROWS  FILTERED  EXTRA
2     100       Using where

Он использует сканирование диапазона по индексу , а затем читает только соответствующие строки из таблицы.

ypercubeᵀᴹ
источник
отличное объяснение и спасибо за sql-fiddle. один комментарий к вашей схеме, который меня на мгновение бросил, это INDEX t_IX (timestamp, id)могло (должно?) просто быть INDEX t_IX (timestamp), поскольку первичный ключ подразумевается в индексе. или есть причина, по которой я этого не понимаю? Я попробовал это в sql-fiddle и увидел тот же (лучший) план выполнения
natbro
1
@natbro Да, если таблица использует механизм InnoDB, то id(потому что это PK и, следовательно, кластерный индекс таблицы) добавляется в индекс в любом случае. Так что явно добавить его не помешает (и это может уловить некоторые слепые зоны оптимизатора). Это конечно не актуально в данном случае / запросе.
ypercubeᵀᴹ 05
Кто-нибудь может объяснить, зачем timestamp < CURDATE() + INTERVAL 1 DAYэто нужно?
Nightwolf
@Nightwolf, потому что у вас могут храниться строки, где значение метки времени находится в будущем. Вопрос требует «только сегодняшние рекорды» .
ypercubeᵀᴹ 03
@ TypoCubeᵀᴹ Ага, не учел, что чисто потому, что timestamp не будет делать будущие даты. Тем не менее, следует иметь в виду.
Nightwolf
12
SELECT * FROM `table` WHERE timestamp >= CURDATE()

он короче, нет необходимости использовать 'AND timestamp <CURDATE () + INTERVAL 1 DAY'

потому что CURDATE () всегда возвращает текущий день

Функция MySQL CURDATE ()

Хамед Персия
источник
1
a) Вопрос требует «только сегодняшние записи», и ваш код также получает будущие даты. б) Ваше сравнение не работает, вы должны сделать это с DATE (отметка времени). Другими словами: если вы исправите свой ответ, вы получите исходный ответ @JohnWoo.
Катапофатико,
3

Сколько способов снять шкуру с этой кошки? Вот еще один вариант.

ВЫБРАТЬ * ОТ tableГДЕ ДАТА (FROM_UNIXTIME ( timestamp)) = '2015-11-18';

стефгосселин
источник
3

Если вы хотите сравнить с определенной датой, вы можете написать ее так:

select * from `table_name` where timestamp >= '2018-07-07';

// здесь временная метка - это имя столбца, имеющего тип как временная метка

или

Для получения сегодняшней даты доступна функция CURDATE (), поэтому:

select * from `table_name` where timestamp >=  CURDATE();
ВидитАгарвал
источник
2

Просто приведите его к дате:

SELECT * FROM `table` WHERE CAST(`timestamp` TO DATE) == CAST(NOW() TO DATE)
MarcDefiant
источник
2

На мой взгляд, это может быть проще всего:

SELECT * FROM `table` WHERE `timestamp` like concat(CURDATE(),'%');
Джерри Джонс
источник
1

В Visual Studio 2017, используя встроенную базу данных для разработки, у меня возникли проблемы с текущим заданным решением, мне пришлось изменить код, чтобы заставить его работать, потому что он выдал ошибку, что DATE () не была встроенной функцией.

Вот мое решение:

where CAST(TimeCalled AS DATE) = CAST(GETDATE() AS DATE)

Сезар Бурден Коста
источник
Вы, вероятно, использовали не MySQL, а какую-то другую СУБД (возможно, SQL Server?) Обратите внимание на теги вопроса.
ypercubeᵀᴹ