Come selezionare le righe che hanno il timestamp del giorno corrente?


104

Sto cercando di selezionare solo i record di oggi da una tabella di database.

Attualmente uso

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

Ma questo richiede risultati per le ultime 24 ore e ho bisogno che selezioni solo i risultati di oggi, ignorando l'ora. Come posso selezionare i risultati solo in base alla data?

Risposte:


191

utilizzare DATEeCURDATE()

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

Immagino che l' utilizzo DATE utilizzi ancora INDEX .

vedere il piano di esecuzione sulla DEMO


Vedere la differenza: SQL-Fiddle Notare FILTERATO = 25 nella seconda query.
ypercubeᵀᴹ

@ypercube oh mi mancava, ma mi chiedevo perché il valore in più Using where; Using index?
John Woo

1
L'indice viene utilizzato per selezionare le righe. Ma l'intero indice viene scansionato (e tutti i valori vengono convertiti con DATE () per valutare la condizione) con la query. Aggiornerò la mia risposta con un esempio migliore.
ypercubeᵀᴹ

1
con tutto il rispetto, la soluzione ypercube è migliore per motivi di prestazioni, se il tuo tavolo ha centinaia di migliaia di righe, dovresti assolutamente andare in questa direzione
Vincent

1
le `` sono importanti perché timestamp(e datecome nel mio caso) è una parola riservata MySQL
Victor Ferreira

55

Se desideri che venga utilizzato un indice e la query non esegua una scansione della tabella:

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

Per mostrare la differenza che questo fa sui piani di esecuzione effettivi, testeremo con un SQL-Fiddle (un sito estremamente 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') ;

Proviamo ora le 2 versioni.


Versione 1 con DATE(timestamp) = ?

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

Spiegare:

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

ROWS  FILTERED  EXTRA
6671  100       Using where; Using filesort

Si filtra tutti (6671) le righe e poi fa un FileSort (che non è un problema in quanto le righe restituite sono pochi)


Versione 2 con timestamp <= ? AND timestamp < ?

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

Spiegare:

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

Utilizza una scansione dell'intervallo sull'indice e quindi legge solo le righe corrispondenti dalla tabella.


ottima spiegazione e grazie per sql-fiddle. un commento sul tuo schema che mi ha lanciato per un momento, che INDEX t_IX (timestamp, id)potrebbe (dovrebbe?) essere INDEX t_IX (timestamp), poiché la chiave primaria è implicita nell'indice. o c'è una ragione che non capisco per farlo? L'ho provato in sql-fiddle e ho visto lo stesso (migliore) piano di esecuzione
natbro

1
@natbro Sì, se la tabella utilizza il motore InnoDB, il id(perché è il PK e quindi l'indice cluster della tabella) viene comunque aggiunto all'indice. Quindi, non fa male aggiungerlo esplicitamente (e potrebbe cogliere alcuni punti ciechi dell'ottimizzatore). Certamente non è rilevante in questo caso / query.
ypercubeᵀᴹ

Qualcuno può spiegare perché timestamp < CURDATE() + INTERVAL 1 DAYè necessario?
Nightwolf

@ Nightwolf perché potresti avere delle righe memorizzate in cui il valore del timestamp è in futuro. La domanda chiede "solo i record di oggi" .
ypercubeᵀᴹ

@ TypoCubeᵀᴹ Aha, non l'ho considerato puramente perché il timestamp non farà date future. Tuttavia un buon punto da tenere a mente.
Nightwolf

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

è più breve, non è necessario utilizzare "AND timestamp <CURDATE () + INTERVAL 1 DAY"

perché CURDATE () restituisce sempre il giorno corrente

Funzione MySQL CURDATE ()


a) La domanda richiede "solo record di oggi" e il tuo codice ottiene anche date future. b) Il tuo confronto non funziona, devi farlo con DATE (timestamp) In altre parole: se aggiusti la tua risposta, otterrai la risposta originale @JohnWoo.
Katapofatico

2

In quanti modi possiamo scuoiare questo gatto? Ecco un'altra variante.

SELEZIONA * FROM tableWHERE DATE (FROM_UNIXTIME ( timestamp)) = '2015-11-18';


2

Se vuoi fare un confronto con una data particolare, puoi scriverlo direttamente come:

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

// qui il timestamp è il nome della colonna avente type come timestamp

o

Per il recupero della data odierna, è disponibile la funzione CURDATE (), quindi:

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

1

Trasmettilo semplicemente a una data:

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

1

Questo potrebbe essere il più semplice secondo me:

SELECT * FROM `table` WHERE `timestamp` like concat(CURDATE(),'%');


0

Su Visual Studio 2017, utilizzando il database integrato per lo sviluppo ho avuto problemi con la soluzione data corrente, ho dovuto modificare il codice per farlo funzionare perché ha generato l'errore che DATE () non era una funzione incorporata.

Ecco la mia soluzione:

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


Probabilmente non stavi usando MySQL ma qualche altro DBMS (forse SQL Server?) Notare i tag della domanda.
ypercubeᵀᴹ
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.