Il "tra" di MS SQL Server include i limiti dell'intervallo?


234

Ad esempio possibile

SELECT foo
FROM bar
WHERE foo BETWEEN 5 AND 10

selezionare 5 e 10 o sono esclusi dall'intervallo?

Risposte:


258

L'operatore TRA è inclusivo.

Dai libri online:

TRA restituisce VERO se il valore di test_expression è maggiore o uguale al valore di begin_expression e minore o uguale al valore di end_expression.

DateTime Caveat

NB: con DateTimes devi stare attento; se viene fornita solo una data, il valore viene preso a partire dalla mezzanotte di quel giorno; per evitare tempi mancanti entro la data di fine o ripetere l'acquisizione dei dati del giorno seguente a mezzanotte in più intervalli, la data di fine dovrebbe essere di 3 millisecondi prima della mezzanotte del giorno successivo a quello attuale. 3 millisecondi perché non inferiore a questo e il valore verrà arrotondato alla mezzanotte del giorno successivo.

ad es. per ottenere tutti i valori entro giugno 2016 dovresti eseguire:

where myDateTime between '20160601' and DATEADD(millisecond, -3, '20160701')

vale a dire

where myDateTime between '20160601 00:00:00.000' and '20160630 23:59:59.997'

datetime2 e datetimeoffset

Sottraendo 3 ms da una data, sarai vulnerabile alle righe mancanti dalla finestra di 3 ms. La soluzione corretta è anche la più semplice:

where myDateTime >= '20160601' AND myDateTime < '20160701'

11
Quando si utilizza BETWEEN per filtrare DateTimes tra due date, è anche possibile trasmettere DateTime a una data, ad esempio: dove CONVERT (DATA, MyDate) TRA '2017-09-01' e '2017-09-30' Questo approccio fa il tempo elemento del DateTime irrilevante
Pete

1
Assicurati di non provare a sottrarre 3 ms da una data; ti mancheranno oggetti di quei 3 ms. E anche tu non vuoi CONVERTun datetime a una data , poiché ciò renderà gli indici inutili. Usa lo standard WHERE OrderDate >= '20160601' AND OrderDate < '20160701'. Inoltre, assicurati di utilizzare yyyymmdd, poiché yyyy-mm-dddipende dalle mdy, dmy, ymd, ydm, myd, and dymimpostazioni locali e verrà interpretato erroneamente in base alle impostazioni del tuo server .
Ian Boyd,

254

Sì, ma fai attenzione quando usi tra per le date.

BETWEEN '20090101' AND '20090131'

è davvero interpretato come 12am o

BETWEEN '20090101 00:00:00' AND '20090131 00:00:00'

così mancherà tutto ciò che è accaduto durante il giorno del 31 gennaio. In questo caso, dovrai usare:

myDate >= '20090101 00:00:00' AND myDate < '20090201 00:00:00'  --CORRECT!

o

BETWEEN '20090101 00:00:00' AND '20090131 23:59:59' --WRONG! (see update!)

AGGIORNAMENTO : È possibile creare dei record nell'ultimo secondo della giornata, con un datetime fino al 20090101 23:59:59.997!!

Per questo motivo, l' BETWEEN (firstday) AND (lastday 23:59:59)approccio non è raccomandato.

Usa myDate >= (firstday) AND myDate < (Lastday+1)invece l' approccio.

Buon articolo su questo problema qui .


1
Problemi simili anche con le stringhe WHERE col BETWEEN 'a' AND 'z'escluderanno ad esempio la maggior parte delle righe z.
Martin Smith,

8
Questo punto è giusto ovviamente; ma non dovrebbe essere sorprendente se stai lavorando con i tempi dei dati. È analogo sottolineare che BETWEEN 5 AND 10non include 10.2...
Andrzej Doyle,

4
CASTzione del datetimecome DATEavrebbe funzionato: CAST(DATE_TIME_COL AS DATE) BETWEEN '01/01/2009' AND '01/31/2009'.
Craig

2
@craig, è vero, purché si utilizzi SQL 2008 o versioni successive, ovvero quando è stato introdotto il tipo di dati Date. Inoltre, quella sintassi convertirà quel valore per ogni singola riga, quindi non sarà possibile utilizzare alcun indice su quel campo (se questo è un problema).
BradC,

It is entirely possible to have records created within that last second of the day, with a datetime as late as 01/01/2009 23:59:59.997<- non puoi usare solo allora AND '01/31/2009 23:59:59.99999999'o comunque sono necessari molti 9
wal

16

Esempio reale da SQL Server 2008.

Dati di origine:

ID    Start
1     2010-04-30 00:00:01.000
2     2010-04-02 00:00:00.000
3     2010-05-01 00:00:00.000
4     2010-07-31 00:00:00.000

Query:

SELECT
    *
FROM
    tbl
WHERE
    Start BETWEEN '2010-04-01 00:00:00' AND '2010-05-01 00:00:00'

risultati:

ID    Start
1     2010-04-30 00:00:01.000
2     2010-04-02 00:00:00.000

testo alternativo


Non ho ricevuto la tua risposta, a dire il vero. Forse il mio provider Internet ha nascosto il tuo screenshot se ne hai pubblicato uno.
anar khalilov,

2
Perché la riga è ID = 3esclusa? Il suo Startvalore è uguale al BETWEENvalore con limite superiore ed BETWEENè un intervallo inclusivo, non un intervallo con limite superiore esclusivo.
Dai

Migliore risposta con risultati.
Sam

13

se lo colpisci e non vuoi davvero provare a gestire l'aggiunta di un giorno nel codice, lascia che il DB lo faccia ..

myDate >= '20090101 00:00:00' AND myDate < DATEADD(day,1,'20090101 00:00:00')

Se includi la parte temporale: assicurati che faccia riferimento a mezzanotte. Altrimenti puoi semplicemente omettere il tempo:

myDate >= '20090101' AND myDate < DATEADD(day,1,'20090101')

e non preoccuparti.


12

TRA (Transact-SQL)

Specifica un intervallo ( n ) ( inclusivo ) da testare.

test_expression [ NOT ] BETWEEN begin_expression AND end_expression

argomenti

test_expression

Espressione da testare nell'intervallo definito da begin_expression e end_expression. test_expression deve essere dello stesso tipo di dati sia begin_expression che end_expression.

NOT

Specifica che il risultato del predicato deve essere negato.

begin_expression

Qualsiasi espressione valida. begin_expression deve essere dello stesso tipo di dati di test_expression e end_expression.

end_expression

Qualsiasi espressione valida. end_expression deve essere dello stesso tipo di dati di test_expression e begin_expression.

AND

Agisce come segnaposto che indica test_expression deve essere compreso nell'intervallo indicato da begin_expression e end_expression.

Osservazioni

Per specificare un intervallo esclusivo, utilizzare gli operatori maggiore di (>) e minore di (<). Se qualsiasi input per il predicato TRA o NON TRA è NULL, il risultato è SCONOSCIUTO.

Valore risultato

TRA restituisce VERO se il valore di test_expression è maggiore o uguale al valore di begin_expression e minore o uguale al valore di end_expression.

NON TRA restituisce VERO se il valore di test_expression è inferiore al valore di begin_expression o maggiore del valore di end_expression.


3

Se il tipo di dati della colonna è datetime, è possibile procedere come segue per eliminare l'ora dal datetime e confrontare solo tra intervalli di date.

where cast(getdate() as date) between cast(loginTime as date) and cast(logoutTime as date)

Funziona meglio dell'aggiunta di +1 alla data di fine. Concordo con Andrew Morton: se non è possibile effettuare la sarginabilità, è possibile migliorare le prestazioni per modificare il tipo di dati della colonna o aggiungere una seconda colonna con solo date pre-calcolate.
Arno Peters,

0

Include i confini.

declare @startDate date = cast('15-NOV-2016' as date) 
declare @endDate date = cast('30-NOV-2016' as date)
create table #test (c1 date)
insert into #test values(cast('15-NOV-2016' as date))
insert into #test values(cast('20-NOV-2016' as date))
insert into #test values(cast('30-NOV-2016' as date))
select * from #test where c1 between @startDate and @endDate
drop table #test
RESULT    c1
2016-11-15
2016-11-20
2016-11-30


declare @r1 int  = 10
declare @r2 int  = 15
create table #test1 (c1 int)
insert into #test1 values(10)
insert into #test1 values(15)
insert into #test1 values(11)
select * from #test1 where c1 between @r1 and @r2
drop table #test1
RESULT c1
10
11
15

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.