La clausola "Between" di MySQL non include?


142

Se eseguo una query con una betweenclausola, sembra escludere il valore finale.
Per esempio:

select * from person where dob between '2011-01-01' and '2011-01-31'

Questo ottiene tutti i risultati con dob"2011-01-01" fino a "2011-01-30"; saltando i record dove si dobtrova "31-01-2011". Qualcuno può spiegare perché questa query si comporta in questo modo e come potrei modificarla per includere i record dove si dobtrova "2011-01-31"? (senza aggiungere 1 alla data di fine perché è stato selezionato dagli utenti.)


No. La mia installazione di MySQL (versione?) BETWEENÈ comprensiva di entrambi i valori. Ho MySQL Server 5.7su Windows 10.
Green

Risposte:


181

Il campo dobha probabilmente una componente temporale.

Per troncarlo:

select * from person 
where CAST(dob AS DATE) between '2011-01-01' and '2011-01-31'

59
Invece di CAST(dob AS DATE)te puoi usare il più succinto DATE(dob).
jkndrkn,

11
Mentre funziona, otterrai prestazioni migliori usando >=e <invece di between.
David Harkness,

112
Otterrai prestazioni migliori utilizzando dob BETWEEN '2011-01-01 00:00:00' AND '2011-01-31 23:59:59. Questo perché DATE(dob)deve calcolare un valore per ogni riga e non può utilizzare alcun indice su quel campo.
joshuahedlund,

2
@joshuahedlund Aggiungi una risposta con questa soluzione. CAST non è così efficiente.
doc_id

3
@joshuahedlund Funziona fino a quando non si hanno dati con i tempi t > 23:59:59 and t < 24:00:00. Perché trattare con poco specificato BETWEEN? Piuttosto seguire il consiglio e l'uso di David: WHERE dob >= '2011-01-01' AND dob < '2011-02-01'. Le migliori prestazioni e funziona sempre.
Disilluso il

300

Dal manuale di MySQL :

Questo è equivalente all'espressione (min <= expr AND expr <= max)


3
Il manuale collegato in questa risposta mostra che è preferibile un cast quando si confrontano oggetti DATE e DATETIME. Quindi immagino che @tiagoinu abbia la risposta più completa nel senso più stretto, ma entrambi sono esatti.
Kingsolmn,

@jemminger potrebbe essere perché la risposta è dell'archrival -postgres guy: P
nawfal,

27
In breve tra è inclusivo ... ecco perché questa risposta oscilla.
Rafael,

6
Vecchio commento, ma volevo associarlo alla query specifica. "TRA" è inclusivo, ma le date senza orario specificato sono alle 00:00:00. Il confronto su un intervallo di date perderà quindi l'ultimo giorno. Chiama DATE (dob) o specifica la fine della giornata.
wintermute92,

dicono che la pratica è oro, dal mio caso d'uso non è affatto inclusivo, mi chiedo perché questo accada con me. Ho provato e a volte funziona a volte no. usandolo sul campo dati TIME.
Jeffery ThaGintoki,

99

Il problema è che il 2011-01-31 è in realtà il 2011-01-31 00:00:00. Questo è l'inizio della giornata. Tutto durante il giorno non è incluso.


19
Questo spiega davvero cosa sta succedendo e risponde alla domanda.
Ivan P,

3
Dopo tutti quegli anni questa risposta è ancora la migliore. Molte grazie.
Strabek,

31
select * from person where dob between '2011-01-01 00:00:00' and '2011-01-31 23:59:59'

1
Io penso che la pena notare che, questo non includerà date a 2011-01-31 23:59:59ma includerà quelli fino 2011-01-31 23:59:58 all'ultimo secondo della giornata non è incluso Potrebbe essere minore, ma qualcuno potrà beneficiare.
doc_id

1
rahmanisback dalla documentazione di MySQL Posso confermare che l'ultimo secondo sarà incluso poiché TRA è compreso in entrambi i modi. fare riferimento a dev.mysql.com/doc/refman/5.5/en/…
Felype

1
Sì, @Felype hai ragione. Ho controllato questo nel database mysql. Include anche 23:59:59il risultato. Quindi è inclusivo in entrambi i modi.
Lucky

2
Se la dobcolonna è un timestamp con precisione sub-second, allora non BETWEENmancheranno ancora gli eventi nell'ultimo secondo del giorno a meno che non venga utilizzato "2011-02-01 00:00:00"?
azoto

1
-1. Non includerò 2011-01-31 23:59:59.003. @nitrogen utilizzando 2011-02-01 000:00:00sarà in modo non corretto includere tempo zero il 1 ° febbraio .... Che è il motivo per cui >=e <dovrebbe essere usato al posto.
Disilluso il

6

Il campo a cui fai riferimento nella tua query è un tipo di data o un tipo di DateTime ?

Una causa comune del comportamento descritto è quando si utilizza un tipo DateTime in cui si dovrebbe realmente utilizzare un tipo di data. Cioè, a meno che tu non abbia davvero bisogno di sapere a che ora è nato qualcuno, usa solo il tipo di Data.

Il motivo per cui l'ultimo giorno non viene incluso nei risultati è il modo in cui la query assume la parte temporale delle date non specificate nella query.

Vale a dire: la tua query viene interpretata fino a mezzanotte tra il 30-01-2011 e il 31-01-2011, ma i dati potrebbero avere un valore più tardi nel giorno 2011-01-31.

Suggerimento: modificare il campo nel tipo Data se si tratta di un tipo DateTime.


4

Ciao questa query funziona per me,

select * from person where dob between '2011-01-01' and '2011-01-31 23:59:59'

2
select * from person where DATE(dob) between '2011-01-01' and '2011-01-31'

Sorprendentemente tali conversioni sono soluzioni a molti problemi in MySQL.


10
Sorprendentemente, questo è esattamente ciò che la risposta accettata (e molti altri) ha detto ... 2 anni prima di te.
Chris Baker,

0

Imposta la data superiore fino ad oggi + 1 giorno, quindi, nel tuo caso, impostala su 01-02-2011.


1
Ciò includerà erroneamente il tempo zero il 1 ° febbraio .... Ecco perché BETWEENdovrebbe essere ignorato; ma >=e <dovrebbe essere usato invece.
Disilluso il

0

È possibile eseguire la query come:

select * from person where dob between '2011-01-01' and '2011-01-31 23:59:59'

come altri hanno sottolineato, se le tue date sono codificate.

D'altra parte, se la data è in un'altra tabella, puoi aggiungere un giorno e sottrarre un secondo (se le date vengono salvate senza il secondo / orario), come:

select * from person JOIN some_table ... where dob between some_table.initial_date and (some_table.final_date + INTERVAL 1 DAY - INTERVAL 1 SECOND)

Evitare di eseguire cast sui dobcampi (come nella risposta accettata), perché ciò può causare enormi problemi di prestazioni (come non essere in grado di utilizzare un indice sul dobcampo, supponendo che ce ne sia uno). Il piano di esecuzione può cambiare da using index conditiona using wherese fai qualcosa di simile DATE(dob)o CAST(dob AS DATE), quindi fai attenzione!


0

In MySql tra i valori sono compresi quindi quando si tenta di passare tra "01-01-2011" e "31-01-2011"

includerà da 2011-01-01 00:00:00upto 2011-01-31 00:00:00 quindi nulla in realtà nel 2011-01-31 poiché il suo tempo dovrebbe passare2011-01-31 00:00:00 ~ 2011-01-31 23:59:59

Per il limite superiore è possibile passare a, 2011-02-01quindi tutti i dati verranno aggiornati2011-01-31 23:59:59

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.