Có phải giữa các SQL của MS SQL Server bao gồm các ranh giới phạm vi không?


234

Ví dụ có thể

SELECT foo
FROM bar
WHERE foo BETWEEN 5 AND 10

chọn 5 và 10 hoặc chúng được loại trừ khỏi phạm vi?

Câu trả lời:


258

Toán tử BETweEN đã bao gồm.

Từ sách trực tuyến:

GIỮA trả về ĐÚNG nếu giá trị của test_expression lớn hơn hoặc bằng giá trị của start_expression và nhỏ hơn hoặc bằng giá trị của end_expression.

Cảnh báo ngày giờ

NB: Với DateTimes bạn phải cẩn thận; nếu chỉ một ngày được đưa ra, giá trị được lấy vào lúc nửa đêm của ngày đó; để tránh bỏ lỡ thời gian trong ngày kết thúc của bạn hoặc lặp lại việc thu thập dữ liệu của ngày hôm sau vào lúc nửa đêm trong nhiều phạm vi, ngày kết thúc của bạn phải là 3 mili giây trước nửa đêm vào ngày sau ngày của bạn. 3 mili giây vì bất kỳ ít hơn mức này và giá trị sẽ được làm tròn đến nửa đêm vào ngày hôm sau.

ví dụ: để có được tất cả các giá trị trong tháng 6 năm 2016 bạn cần chạy:

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

I E

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

datetime2 và datetimeoffset

Trừ 3 ms từ một ngày sẽ khiến bạn dễ bị thiếu các hàng từ cửa sổ 3 ms. Giải pháp đúng cũng là cách đơn giản nhất:

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

11
Khi sử dụng GIỮA để lọc DateTimes giữa hai ngày, bạn cũng có thể truyền DateTime thành một ngày, ví dụ: nơi CHUYỂN ĐỔI (NGÀY, MyDate) GIỮA '2017-09-01' và '2017-09-30' Cách tiếp cận này tạo ra thời gian yếu tố của DateTime không liên quan
Pete

1
Hãy chắc chắn không cố gắng trừ 3 ms từ một ngày; bạn sẽ bỏ lỡ các mục từ 3 ms. Và bạn cũng không muốn CONVERTmột datetime đến một ngày , vì điều đó sẽ làm cho chỉ số vô dụng. Sử dụng tiêu chuẩn WHERE OrderDate >= '20160601' AND OrderDate < '20160701'. Ngoài ra, hãy chắc chắn sử dụng yyyymmdd, yyyy-mm-ddtùy thuộc vào miền địa phương và sẽ bị hiểu sai tùy thuộc vào mdy, dmy, ymd, ydm, myd, and dymcài đặt máy chủ của bạn .
Ian Boyd

254

Có, nhưng hãy cẩn thận khi sử dụng giữa các ngày.

BETWEEN '20090101' AND '20090131'

thực sự được hiểu là 12 giờ sáng, hoặc

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

vì vậy sẽ bỏ lỡ bất cứ điều gì xảy ra trong ngày 31 tháng 1. Trong trường hợp này, bạn sẽ phải sử dụng:

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

hoặc là

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

CẬP NHẬT : Hoàn toàn có thể có các bản ghi được tạo trong giây cuối cùng của ngày, với thời gian muộn nhất là 20090101 23:59:59.997!!

Vì lý do này, BETWEEN (firstday) AND (lastday 23:59:59)cách tiếp cận không được khuyến khích.

Sử dụng myDate >= (firstday) AND myDate < (Lastday+1)phương pháp thay thế.

Bài viết tốt về vấn đề này ở đây .


1
Các vấn đề tương tự với các chuỗi cũng WHERE col BETWEEN 'a' AND 'z'sẽ loại trừ hầu hết các hàng z chẳng hạn.
Martin Smith

8
Điểm này là tất nhiên; nhưng không nên ngạc nhiên nếu bạn đang làm việc với datetimes. Nó tương tự như chỉ ra rằng BETWEEN 5 AND 10không bao gồm 10.2...
Andrzej Doyle

4
CASTing datetimenhư là DATEsẽ làm việc : CAST(DATE_TIME_COL AS DATE) BETWEEN '01/01/2009' AND '01/31/2009'.
craig

2
@craig, điều đó đúng, miễn là bạn đang sử dụng SQL 2008 trở lên, đó là khi kiểu dữ liệu Ngày được giới thiệu. Ngoài ra, cú pháp đó sẽ chuyển đổi giá trị đó cho mỗi hàng đơn, vì vậy sẽ không thể sử dụng bất kỳ chỉ mục nào trên trường đó (nếu đó là một mối quan tâm).
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<- bạn không thể sử dụng sau đó AND '01/31/2009 23:59:59.99999999'hoặc tuy nhiên nhiều số 9 được yêu cầu
wal

16

Ví dụ thế giới thực từ SQL Server 2008.

Nguồn dữ liệu:

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

Truy vấn:

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

Các kết quả:

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

văn bản thay thế


Tôi đã không nhận được câu trả lời của bạn, thành thật mà nói. Có thể nhà cung cấp internet của tôi đã ẩn ảnh chụp màn hình của bạn nếu bạn đăng.
anar khalilov

2
Tại sao hàng ID = 3bị loại trừ? StartGiá trị của nó bằng với BETWEENgiá trị giới hạn trên và BETWEENlà một phạm vi bao gồm, không phải là phạm vi giới hạn trên độc quyền.
Đại

Trả lời tốt hơn với kết quả.
Sam

13

nếu bạn nhấn vào đây và không thực sự muốn thử và xử lý thêm một ngày vào mã, thì hãy để DB làm điều đó ..

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

Nếu bạn bao gồm phần thời gian: hãy chắc chắn rằng nó tham chiếu vào nửa đêm. Nếu không, bạn chỉ có thể bỏ qua thời gian:

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

và không lo lắng về nó.


12

GIỮA (Giao dịch-SQL)

Chỉ định phạm vi ( n ) ( bao gồm ) để kiểm tra.

test_expression [ NOT ] BETWEEN begin_expression AND end_expression

Tranh luận

test_expression

Là biểu thức để kiểm tra trong phạm vi được xác định bởi Begin_expression và end_expression. test_expression phải cùng loại dữ liệu với cả start_expression và end_expression.

NOT

Chỉ định rằng kết quả của vị từ bị phủ định.

begin_expression

Là bất kỳ biểu thức hợp lệ. started_expression phải cùng loại dữ liệu với cả test_expression và end_expression.

end_expression

Là bất kỳ biểu thức hợp lệ. end_expression phải cùng loại dữ liệu với cả test_expression và started_expression.

AND

Hành vi như một trình giữ chỗ chỉ ra test_expression phải nằm trong phạm vi được chỉ định bởi Begin_expression và end_expression.

Nhận xét

Để chỉ định phạm vi độc quyền, sử dụng phạm vi lớn hơn (>) và nhỏ hơn toán tử (<). Nếu bất kỳ đầu vào nào của vị từ GIỮA hoặc KHÔNG GIỮA là NULL, thì kết quả là UNKNOWN.

Giá trị kết quả

GIỮA trả về ĐÚNG nếu giá trị của test_expression lớn hơn hoặc bằng giá trị của start_expression và nhỏ hơn hoặc bằng giá trị của end_expression.

KHÔNG GIỮA trả về ĐÚNG nếu giá trị của test_expression nhỏ hơn giá trị của start_expression hoặc lớn hơn giá trị của end_expression.


3

Nếu kiểu dữ liệu cột là datetime thì bạn có thể làm như sau để loại bỏ thời gian khỏi datetime và chỉ so sánh giữa phạm vi ngày.

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

Điều này hoạt động tốt hơn so với việc thêm +1 vào ngày kết thúc. Tôi đồng ý với Andrew Morton - nếu không thể thực hiện được, nó có thể cải thiện hiệu suất để thay đổi loại dữ liệu cột hoặc thêm cột thứ hai chỉ với các ngày được tính toán trước.
Arno Peters

0

Nó bao gồm các ranh giới.

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

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.