Comment sélectionner des lignes qui ont l'horodatage du jour actuel?

104

J'essaie de sélectionner uniquement les enregistrements d'aujourd'hui à partir d'une table de base de données.

J'utilise actuellement

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

Mais cela prend des résultats pour les dernières 24 heures, et j'en ai besoin pour ne sélectionner que les résultats d'aujourd'hui, en ignorant l'heure. Comment puis-je sélectionner des résultats en fonction de la date uniquement?

Jackie Honson
la source

Réponses:

192

utiliser DATEetCURDATE()

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

Je suppose que l' utilisation DATE utilise toujours INDEX .

voir le plan d'exécution sur la DEMO

John Woo
la source
Voyez la différence: SQL-Fiddle Notez le FILTERED = 25 dans la 2ème requête.
ypercubeᵀᴹ
@ypercube oh j'ai raté ça mais je me demandais pourquoi la valeur en plus Using where; Using index?
John Woo
1
L'index est utilisé pour sélectionner les lignes. Mais l'index entier est analysé (et toutes les valeurs sont converties avec DATE () pour évaluer la condition) avec votre requête. Je mettrai à jour ma réponse avec un meilleur exemple.
ypercubeᵀᴹ
1
avec tout le respect que je vous dois, la solution ypercube est meilleure pour des raisons de performances, si votre table contient des centaines de milliers de lignes, vous devez absolument aller dans cette direction
Vincent
1
le `` sont importants car timestamp(et datecomme dans mon cas) est un mot réservé MySQL
Victor Ferreira
56

Si vous souhaitez qu'un index soit utilisé et que la requête n'effectue pas d'analyse de table:

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

Pour montrer la différence que cela fait sur les plans d'exécution réels, nous allons tester avec un SQL-Fiddle (un site extrêmement utile):

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

Essayons les 2 versions maintenant.


Version 1 avec DATE(timestamp) = ?

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

Explique:

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

ROWS  FILTERED  EXTRA
6671  100       Using where; Using filesort

Il filtre toutes les (6671) lignes puis effectue un tri de fichiers (ce n'est pas un problème car les lignes renvoyées sont peu nombreuses)


Version 2 avec timestamp <= ? AND timestamp < ?

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

Explique:

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

Il utilise une analyse de plage sur l'index , puis lit uniquement les lignes correspondantes de la table.

ypercubeᵀᴹ
la source
bonne explication et merci pour le sql-fiddle. un commentaire sur votre schéma qui m'a jeté pendant un moment, cela INDEX t_IX (timestamp, id)pourrait (devrait?) être juste INDEX t_IX (timestamp), comme la clé primaire est impliquée dans l'index. ou y a-t-il une raison pour laquelle je ne comprends pas pour faire ça? Je l'ai essayé dans sql-fiddle et j'ai vu le même (meilleur) plan d'exécution
natbro
1
@natbro Oui, si la table utilise le moteur InnoDB, le id(car c'est le PK et donc l'index clusterisé de la table) est quand même ajouté dans l'index. Donc, cela ne fait pas de mal de l'ajouter explicitement (et cela peut attraper certains angles morts de l'optimiseur). Ce n'est certainement pas pertinent dans ce cas / requête.
ypercubeᵀᴹ
Quelqu'un peut-il expliquer pourquoi timestamp < CURDATE() + INTERVAL 1 DAYest nécessaire?
Nightwolf
@Nightwolf parce que vous pouvez avoir des lignes stockées là où la valeur d'horodatage est dans le futur. La question demande "seulement les enregistrements d'aujourd'hui" .
ypercubeᵀᴹ
@ TypoCubeᵀᴹ Aha, n'a pas considéré cela uniquement parce que l'horodatage ne fera pas les dates futures. Néanmoins, bon point à garder à l'esprit.
Nightwolf
11
SELECT * FROM `table` WHERE timestamp >= CURDATE()

il est plus court, il n'est pas nécessaire d'utiliser 'AND timestamp <CURDATE () + INTERVAL 1 DAY'

car CURDATE () renvoie toujours le jour actuel

Fonction MySQL CURDATE ()

Hamed Persia
la source
a) La question demande "seulement les enregistrements d'aujourd'hui", et votre code reçoit également les dates futures. b) Votre comparaison ne fonctionne pas, vous devez le faire avec DATE (horodatage) En d'autres termes: Si vous corrigez votre réponse, vous obtiendrez la réponse originale @JohnWoo.
Katapofatico le
2

De combien de façons pouvons-nous écorcher ce chat? Voici encore une autre variante.

SELECT * FROM tableWHERE DATE (FROM_UNIXTIME ( timestamp)) = '18/11/2015';

stefgosselin
la source
2

Si vous souhaitez comparer avec une date particulière, vous pouvez l'écrire directement comme:

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

// ici l'horodatage est le nom de la colonne ayant le type comme horodatage

ou

Pour récupérer la date du jour, la fonction CURDATE () est disponible, donc:

select * from `table_name` where timestamp >=  CURDATE();
ViditAgarwal
la source
1

Envoyez-le simplement à une date:

SELECT * FROM `table` WHERE CAST(`timestamp` TO DATE) == CAST(NOW() TO DATE)
MarcDéfiant
la source
1

Cela pourrait être le plus simple à mon avis:

SELECT * FROM `table` WHERE `timestamp` like concat(CURDATE(),'%');
Jerry Jones
la source
1

Ou vous pouvez utiliser l'alternative CURRENT_DATE, avec le même résultat:

SELECT * FROM yourtable WHERE created >= CURRENT_DATE

Exemples tirés de database.guide

kochauf
la source
0

Sur Visual Studio 2017, en utilisant la base de données intégrée pour le développement, j'ai eu des problèmes avec la solution actuelle donnée, j'ai dû changer le code pour le faire fonctionner car il a généré l'erreur que DATE () n'était pas une fonction intégrée.

Voici ma solution:

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

Cesar Bourdain Costa
la source
Vous n'utilisiez probablement pas MySQL mais un autre SGBD (SQL Server peut-être?) Notez les balises de la question.
ypercubeᵀᴹ