Як вибрати рядки з часовою позначкою поточного дня?


104

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

В даний час використовую

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

Але це вимагає результатів протягом останніх 24 годин, і мені потрібно, щоб лише сьогодні підбирати результати, ігноруючи час. Як я можу вибрати результати лише на основі дати?

Відповіді:


191

використання DATEтаCURDATE()

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

Я думаю, що при використанні DATE все ще використовується INDEX .

див. план виконання на DEMO


Дивіться різницю: SQL-Fiddle Зауважте ФІЛЬТРОВАНО = 25 у другому запиті.
ypercubeᵀᴹ

@ypercube о, я пропустив це, але мені було цікаво, чому це значення додаткового Using where; Using index?
Джон Ву

1
Індекс використовується для вибору рядків. Але весь індекс сканується (і всі значення перетворюються з DATE () для оцінки умови) з вашим запитом. Я оновлю свою відповідь кращим прикладом.
ypercubeᵀᴹ

1
з усією повагою рішення ypercube краще з міркувань продуктивності, якщо на вашому столі є сотні тисяч рядків, ви обов'язково повинні піти в цьому напрямку
Vincent

1
`` важливі, тому що timestampdateяк у моєму випадку) є зарезервоване слово MySQL
Віктор Феррейра

55

Якщо ви хочете використовувати індекс і запит не робити сканування таблиці:

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') ;

Давайте спробуємо 2 версії зараз.


Версія 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

Він використовує сканування діапазону в індексі , а потім зчитує лише відповідні рядки з таблиці.


чудове пояснення і спасибі за sql-скрипку. один коментар до вашої схеми, який кинув мене на мить, що INDEX t_IX (timestamp, id)міг би (повинен бути?) просто так INDEX t_IX (timestamp), оскільки основний ключ мається на увазі в індексі. або є причина, яку я не розумію для цього? Я спробував це у sql-скрипці і побачив той же (кращий) план виконання
natbro

1
@natbro Так, якщо таблиця використовує двигун InnoDB, то id(оскільки це PK і, таким чином, кластерний індекс таблиці), додається в індекс все одно. Тож не завадить явно додавати його (і це може зафіксувати деякі сліпі плями оптимізатора). Це, безумовно, не стосується в цьому випадку / запиту.
ypercubeᵀᴹ

Хтось може пояснити, чому timestamp < CURDATE() + INTERVAL 1 DAYце потрібно?
Нічний вовк

@Nightwolf, тому що, можливо, зберігаються рядки там, де в майбутньому є значення часової позначки. Питання задає "лише сьогоднішні записи" .
ypercubeᵀᴹ

@ TypoCubeᵀᴹ Ага, не вважав це суто тим, що часові позначки не матимуть подальших дат. Тим не менш, добре пам’ятати про це.
Нічний вовк

11
SELECT * FROM `table` WHERE timestamp >= CURDATE()

він коротший, немає необхідності використовувати позначку "AND timeas <CURDATE () + INTERVAL 1 DAY"

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

MySQL CURDATE () Функція


а) Питання задає "лише сьогоднішні записи", а ваш код також отримує дати в майбутньому. b) Ваше порівняння не працює, ви повинні зробити це з DATE (мітка часу) Іншими словами: Якщо ви виправите свою відповідь, ви отримаєте оригінальну відповідь @JohnWoo.
Katapofatico

2

Скількома способами ми можемо зібрати цю кішку? Ось ще один варіант.

ВИБІР * ВІД tableЧОГО ДАТИ (FROM_UNIXTIME ( timestamp)) = '2015-11-18';


2

Якщо ви хочете порівняти з конкретною датою, ви можете безпосередньо записати це так:

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

// тут часова марка - це ім'я стовпця, що має тип часової позначки

або

Для отримання сьогоднішньої дати доступна функція CURDATE (), тож:

select * from `table_name` where timestamp >=  CURDATE();

1

Просто призначте його на побачення:

SELECT * FROM `table` WHERE CAST(`timestamp` TO DATE) == CAST(NOW() TO DATE)



0

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

Ось моє рішення:

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


Напевно, ви не використовували MySQL, але деякі інші СУБД (можливо, SQL Server?) Зауважте теги цього питання.
ypercubeᵀᴹ
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.