Apakah MS SQL Server "antara" termasuk batas kisaran?

234

Misalnya bisa

SELECT foo
FROM bar
WHERE foo BETWEEN 5 AND 10

pilih 5 dan 10 atau mereka dikeluarkan dari rentang?

Lea Verou
sumber

Jawaban:

258

Operator ANTARA bersifat inklusif.

Dari Buku Online:

BETWEEN mengembalikan TRUE jika nilai test_expression lebih besar atau sama dengan nilai begin_expression dan kurang dari atau sama dengan nilai end_expression.

Peringatan DateTime

NB: Dengan DateTimes Anda harus berhati-hati; jika hanya tanggal yang diberikan nilainya diambil pada tengah malam pada hari itu; untuk menghindari waktu yang hilang dalam tanggal akhir Anda, atau mengulangi pengambilan data hari berikutnya pada tengah malam dalam berbagai rentang, tanggal akhir Anda harus 3 milidetik sebelum tengah malam pada hari setelah tanggal Anda. 3 milidetik karena kurang dari ini dan nilainya akan dibulatkan hingga tengah malam pada hari berikutnya.

mis. untuk mendapatkan semua nilai dalam bulan Juni 2016 Anda harus menjalankan:

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

yaitu

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

datetime2 dan datetimeoffset

Mengurangi 3 ms dari tanggal akan membuat Anda rentan terhadap baris yang hilang dari jendela 3 ms. Solusi yang benar juga merupakan yang paling sederhana:

where myDateTime >= '20160601' AND myDateTime < '20160701'
DJ.
sumber
11
Saat menggunakan BETWEEN untuk memfilter DateTimes di antara dua tanggal, Anda juga dapat memasukkan DateTime ke Tanggal, misalnya: di mana CONVERT (DATE, MyDate) BETWEEN '2017-09-01' dan '2017-09-30' Pendekatan ini membuat waktu elemen DateTime tidak relevan
Pete
1
Pastikan untuk tidak mencoba mengurangi 3 ms dari tanggal; Anda akan kehilangan item dari 3 ms tersebut. Dan Anda juga tidak ingin CONVERTsebuah datetime ke tanggal , karena itu akan membuat indeks tidak berguna. Gunakan standar WHERE OrderDate >= '20160601' AND OrderDate < '20160701'. Juga, pastikan untuk menggunakan yyyymmdd, karena yyyy-mm-ddtergantung pada lokal, dan akan disalahartikan tergantung pada mdy, dmy, ymd, ydm, myd, and dympengaturan server Anda .
Ian Boyd
254

Ya, tapi berhati-hatilah saat menggunakan antara tanggal.

BETWEEN '20090101' AND '20090131'

benar-benar ditafsirkan sebagai 12:00, atau

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

jadi akan kehilangan apa pun yang terjadi pada hari 31 Januari. Dalam hal ini, Anda harus menggunakan:

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

atau

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

UPDATE : Sangat mungkin untuk memiliki catatan yang dibuat dalam detik terakhir hari itu, dengan waktu paling lambat 20090101 23:59:59.997!!

Karena alasan ini, BETWEEN (firstday) AND (lastday 23:59:59)pendekatan ini tidak direkomendasikan.

Gunakan myDate >= (firstday) AND myDate < (Lastday+1)pendekatan itu sebagai gantinya.

Artikel bagus tentang masalah ini di sini .

BradC
sumber
1
Masalah serupa dengan string juga WHERE col BETWEEN 'a' AND 'z'akan mengecualikan sebagian besar baris z misalnya.
Martin Smith
8
Poin ini tentu saja benar; tetapi seharusnya tidak mengejutkan jika Anda bekerja dengan data. Ini analog dengan menunjukkan bahwa BETWEEN 5 AND 10tidak termasuk 10.2...
Andrzej Doyle
4
CASTing datetimesebagai DATEakan bekerja: CAST(DATE_TIME_COL AS DATE) BETWEEN '01/01/2009' AND '01/31/2009'.
craig
2
@craig, itu benar, selama Anda menggunakan SQL 2008 atau lebih tinggi, yaitu saat datatype Date diperkenalkan. Juga, sintaks itu akan mengonversi nilai itu untuk setiap baris tunggal, jadi tidak akan dapat menggunakan indeks apa pun di bidang itu (jika itu merupakan masalah).
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<- tidak bisakah kamu saat itu menggunakan AND '01/31/2009 23:59:59.99999999'atau bagaimanapun banyak 9 diperlukan
wal
16

Contoh dunia nyata dari SQL Server 2008.

Sumber data:

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

Pertanyaan:

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

Hasil:

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

teks alternatif

Ryan Rodemoyer
sumber
Saya tidak mendapatkan jawaban Anda, jujur ​​saja. Mungkin penyedia internet saya telah menyembunyikan tangkapan layar Anda jika Anda mempostingnya.
anar khalilov
2
Mengapa baris dengan ID = 3dikecualikan? Nilainya Startsama dengan nilai batas BETWEENatas, dan BETWEENmerupakan rentang inklusif, bukan rentang batas atas eksklusif.
Dai
Jawaban yang lebih baik dengan hasil.
Sam
13

jika Anda menekan ini, dan tidak benar-benar ingin mencoba dan menangani menambahkan satu hari dalam kode, maka biarkan DB melakukannya ..

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

Jika Anda memasukkan bagian waktu: pastikan referensi di tengah malam. Kalau tidak, Anda bisa dengan mudah menghilangkan waktu:

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

dan tidak khawatir tentang itu.

Shaun
sumber
12

ANTARA (Transact-SQL)

Menentukan rentang ( n ) ( inklusif ) untuk diuji.

test_expression [ NOT ] BETWEEN begin_expression AND end_expression

Argumen

test_expression

Apakah ekspresi yang akan diuji dalam rentang yang ditentukan oleh begin_expression dan end_expression. test_expression harus tipe data yang sama dengan begin_expression dan end_expression.

NOT

Menentukan bahwa hasil predikat dinegasikan.

begin_expression

Apakah ada ekspresi yang valid. begin_expression harus merupakan tipe data yang sama dengan test_expression dan end_expression.

end_expression

Apakah ada ekspresi yang valid. end_expression harus tipe data yang sama dengan test_expression dan begin_expression.

AND

Bertindak sebagai pengganti yang menunjukkan test_expression harus berada dalam rentang yang ditunjukkan oleh begin_expression dan end_expression.

Catatan

Untuk menentukan rentang eksklusif, gunakan yang lebih besar dari (>) dan kurang dari operator (<). Jika ada input ke predikat ANTARA BETWEEN atau BETWEEN NULL, hasilnya TIDAK DIKETAHUI.

Nilai hasil

BETWEEN mengembalikan TRUE jika nilai test_expression lebih besar atau sama dengan nilai begin_expression dan kurang dari atau sama dengan nilai end_expression.

BUKAN ANTARA mengembalikan TRUE jika nilai test_expression kurang dari nilai begin_expression atau lebih besar dari nilai end_expression.

Russ Cam
sumber
3

Jika tipe data kolom datetime, maka Anda dapat melakukan ini untuk menghilangkan waktu dari datetime dan membandingkan antara rentang tanggal saja.

where cast(getdate() as date) between cast(loginTime as date) and cast(logoutTime as date)
Kahlil Vanz
sumber
Ini berfungsi lebih baik daripada menambahkan +1 ke tanggal akhir. Saya setuju dengan Andrew Morton - jika tidak dapat dilakukan maka dapat meningkatkan kinerja untuk mengubah tipe data kolom atau menambahkan kolom kedua dengan tanggal yang hanya dihitung sebelumnya.
Arno Peters
0

Itu memang termasuk batas-batas.

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
Halim
sumber
-3

Saya selalu menggunakan ini:

DI MANA myDate ANTARA startDate AND (endDate + 1)

pengguna2296528
sumber