SQL: GIỮA với <= và> =


111

Trong SQL Server 2000 và 2005:

  • sự khác biệt giữa hai WHEREmệnh đề là gì?
  • tôi nên sử dụng cái nào cho những trường hợp nào?

Truy vấn 1:

SELECT EventId, EventName
FROM EventMaster
WHERE EventDate BETWEEN '10/15/2009' AND '10/18/2009'

Truy vấn 2:

SELECT EventId, EventName
FROM EventMaster
WHERE EventDate >='10/15/2009'
  AND EventDate <='10/18/2009'

(Chỉnh sửa: Eventdate thứ hai ban đầu bị thiếu, do đó, truy vấn sai cú pháp)


1
Đây là một bản sao gần như trùng lặp với stackoverflow.com/questions/1572840/sql-between-v1-and-v2
mjv

6
không thực sự, việc xử lý datetime hơi khác một chút, cộng với đó là đối với SQL server 2008, và không có cách nào mà Shyju có thể chắc chắn nếu không hỏi rằng câu trả lời sẽ giống với các phiên bản trước.
Irfy

Câu trả lời:


119

Chúng giống hệt nhau: BETWEENlà cách viết tắt cho cú pháp dài hơn trong câu hỏi.

Sử dụng một cú pháp dài hơn thay thế BETWEENkhông hoạt động, ví dụ:

Select EventId,EventName from EventMaster
where EventDate >= '10/15/2009' and EventDate < '10/18/2009'

(Lưu ý <hơn là <=ở điều kiện thứ hai.)


19
Có lẽ bạn nên nhấn mạnh điều kiện thứ hai là '<'. Tôi đã mất một thời gian để phát hiện ra sự khác biệt.
zendar

21
Tôi muốn nói thêm rằng tôi thực sự khuyên bạn không bao giờ sử dụng BETWEEN trừ khi bạn đang xử lý kiểu dữ liệu DATE hoặc đã đảm bảo rằng các giá trị ngày giờ của bạn sẽ không bao giờ có thành phần thời gian. Nhất quán về điều này sẽ giúp ít có khả năng bạn sử dụng BETWEEN do nhầm lẫn thay vì> = và <, đồng thời nhận được một số dữ liệu trong truy vấn mà bạn không cố ý hoặc nghĩ rằng bạn sẽ có thêm một ngày dữ liệu khi bạn không ...
Aaron Bertrand

1
Sẽ có bước biên dịch thứ hai khi BETWEEN được chuyển đổi thành điều kiện? Tôi hiểu điều này là một chút phức tạp nhưng sẽ có thêm một chi phí?
James Scott

1
@xmashallax bởi vì họ là? Làm thế nào họ không phải là?
Tony Andrews,

2
Kỳ lạ ... Tôi nghĩ rằng tôi đã nhầm lẫn bởi các câu hỏi, các văn bản của câu trả lời, các ý kiến và thực tế là mã của tôi rõ ràng là có một lỗi bây giờ =)
xmashallax

37

Họ giống nhau.

Một điều cần cẩn thận, là nếu bạn đang sử dụng điều này vào DATETIME, trận đấu cho ngày kết thúc sẽ là đầu ngày:

<= 20/10/2009

không giống như:

<= 20/10/2009 23:59:59

(nó sẽ phù hợp với <= 20/10/2009 00:00:00.000)


Bạn chỉ có thể sử dụng giữa '2009/10/20' và '2009-10-21' trong trường hợp đó để nắm bắt ngày
David Andrei Ned

4
@DavidAndreiNed cũng sẽ khớp với '2009-10-21 00: 00: 00.000' - có thể không phải những gì bạn muốn.
Hans Ke st ing

2
Bạn muốn trường GIỮA '2009-10-20 00:00:00' VÀ '2009-10-20 23:59:59' hoặc trường> = '2009-10-20 00:00:00' AND trường <= '2009-10-20 23:59:59' là hoàn toàn chắc chắn.
geilt

@geilt Các ví dụ của bạn sẽ bỏ sót bất kỳ điều gì xảy ra trong giây cuối cùng của ngày ... tức là: trong khoảng thời gian từ 23:59:59 đến 00:00:00 ngày hôm sau.
Seth Flowers

00:00:00 là ngày bắt đầu của ngày hôm sau và tại sao tôi sử dụng> = và <= và không> hoặc <. Nhưng nếu bạn muốn nói đến micro giây và bạn lưu trữ chúng thì bạn cũng muốn đặt micro giây cuối cùng và cuối cùng.
geilt

14

Mặc dù BETWEENdễ đọc và dễ bảo trì, tôi hiếm khi khuyên bạn nên sử dụng nó vì nó là khoảng thời gian đóng và như đã đề cập trước đây, điều này có thể là một vấn đề với ngày - ngay cả khi không có thành phần thời gian.

Ví dụ: khi xử lý dữ liệu hàng tháng, người ta thường so sánh ngày tháng BETWEEN first AND last, nhưng trong thực tế, điều này thường dễ viết hơn dt >= first AND dt < next-first(điều này cũng giải quyết được vấn đề về phần thời gian) - vì việc xác định lastthường lâu hơn một bước so với xác định next-first(bằng cách trừ đi một ngày) .

Ngoài ra, một vấn đề khác là giới hạn dưới và giới hạn trên cần phải được chỉ định theo đúng thứ tự (tức là BETWEEN low AND high).


4

Thông thường, không có sự khác biệt - BETWEENtừ khóa không được hỗ trợ trên tất cả các nền tảng RDBMS, nhưng nếu có, hai truy vấn phải giống hệt nhau.

Vì chúng giống hệt nhau, nên thực sự không có sự phân biệt về tốc độ hay bất cứ thứ gì khác - hãy sử dụng cái có vẻ tự nhiên hơn đối với bạn.


4

Như đã đề cập bởi @marc_s, @Cloud, et al. về cơ bản chúng giống nhau đối với một phạm vi đóng.

Nhưng bất kỳ giá trị thời gian phân đoạn nào cũng có thể gây ra sự cố với phạm vi đóng (lớn hơn hoặc bằng và nhỏ hơn hoặc bằng ) trái ngược với phạm vi nửa mở (lớn hơn hoặc bằng và nhỏ hơn ) với giá trị kết thúc sau các cuối cùng có thể ngay lập tức.

Vì vậy, để tránh điều đó truy vấn nên được viết lại thành:

SELECT EventId, EventName
  FROM EventMaster
 WHERE (EventDate >= '2009-10-15' AND
        EventDate <  '2009-10-19')    /* <<<== 19th, not 18th */

BETWEENkhông hoạt động trong các khoảng thời gian nửa mở, tôi luôn xem xét kỹ lưỡng bất kỳ truy vấn ngày / giờ nào sử dụng nó, vì nó có thể là một lỗi.


4

Tôi có một chút ưu tiên BETWEENvì nó giúp người đọc hiểu ngay rằng bạn đang kiểm tra một trường cho một phạm vi . Điều này đặc biệt đúng nếu bạn có các tên trường tương tự trong bảng của mình.

Giả sử bảng của chúng ta có cả a transactiondatevà a transitiondate, nếu tôi đọc

transactiondate between ...

Tôi biết ngay rằng cả hai phần cuối của bài kiểm tra đều chống lại một lĩnh vực này.

Nếu tôi đọc

transactiondate>='2009-04-17' and transactiondate<='2009-04-22'

Tôi phải mất thêm một chút thời gian để đảm bảo hai trường giống nhau.

Ngoài ra, khi một truy vấn được chỉnh sửa theo thời gian, một lập trình viên cẩu thả có thể tách hai trường. Tôi đã thấy rất nhiều truy vấn đại loại như

where transactiondate>='2009-04-17'
  and salestype='A'
  and customernumber=customer.idnumber
  and transactiondate<='2009-04-22'

Nếu họ thử điều này với một BETWEEN, tất nhiên, đó sẽ là một lỗi cú pháp và được sửa ngay lập tức.


3

Tôi nghĩ sự khác biệt duy nhất là số lượng cú pháp trên mỗi truy vấn. BETWEEN chỉ là một cách nói bóng bẩy giống hệt như truy vấn thứ hai.

Có thể có một số khác biệt cụ thể trong RDBMS mà tôi không biết, nhưng tôi không thực sự nghĩ như vậy.


2

Về mặt logic, không có sự khác biệt nào cả. Về mặt hiệu suất, về mặt điển hình, trên hầu hết các DBMS - không có sự khác biệt nào cả.



1

Tuyên bố từ chối trách nhiệm: Mọi thứ dưới đây chỉ là giai thoại và được rút ra trực tiếp từ kinh nghiệm cá nhân của tôi. Bất kỳ ai cảm thấy muốn thực hiện một phân tích thực nghiệm nghiêm ngặt hơn đều được hoan nghênh thực hiện và bỏ phiếu nếu tôi. Tôi cũng biết rằng SQL là một ngôn ngữ khai báo và bạn không cần phải xem xét mã của bạn được xử lý như thế nào khi bạn viết nó, nhưng vì tôi coi trọng thời gian của mình nên tôi làm.

Có vô số câu lệnh tương đương về mặt logic, nhưng tôi sẽ xem xét ba (ish).

Trường hợp 1: Hai so sánh theo thứ tự tiêu chuẩn (Đã sửa thứ tự đánh giá)

A> = MinBound VÀ A <= MaxBound

Trường hợp 2: Đường cú pháp (Thứ tự đánh giá không do tác giả lựa chọn)

GIỮA Giới hạn tối thiểu VÀ Giới hạn tối đa

Trường hợp 3: Hai so sánh theo một thứ tự giáo dục (Thứ tự đánh giá được chọn lúc viết)

A> = MinBound VÀ A <= MaxBound

Hoặc là

A <= MaxBound AND A> = MinBound

Theo kinh nghiệm của tôi, Trường hợp 1 và Trường hợp 2 không có bất kỳ sự khác biệt nhất quán hoặc đáng chú ý nào về hiệu suất vì chúng không biết về tập dữ liệu.

Tuy nhiên, Trường hợp 3 có thể cải thiện đáng kể thời gian thực hiện. Cụ thể, nếu bạn đang làm việc với một tập dữ liệu lớn và tình cờ có một số kiến ​​thức kinh nghiệm về việc liệu A có nhiều khả năng lớn hơn Giới hạn tối đa hay nhỏ hơn Giới hạn tối thiểu hay không bạn có thể cải thiện đáng kể thời gian thực thi bằng cách sử dụng Trường hợp 3 và sắp xếp các phép so sánh cho phù hợp.

Một trường hợp sử dụng mà tôi có là truy vấn một tập dữ liệu lịch sử lớn với các ngày không được lập chỉ mục cho các bản ghi trong một khoảng thời gian cụ thể. Khi viết truy vấn, tôi sẽ biết rõ liệu có nhiều dữ liệu hơn tồn tại TRƯỚC khoảng thời gian được chỉ định hoặc SAU khoảng thời gian được chỉ định hay không và có thể sắp xếp các so sánh của mình cho phù hợp. Tôi đã có thời gian thực thi giảm đi một nửa tùy thuộc vào kích thước của tập dữ liệu, độ phức tạp của truy vấn và số lượng bản ghi được lọc bởi so sánh đầu tiên.


Ừm, cái gì? Trường hợp 3 không có cùng logic như Trường hợp 1 và Trường hợp 2. Nếu bạn muốn xem Acó lớn hơn cả hai giới hạn hay không, thì chỉ cần kiểm tra xem giá trị Acó lớn hơn không MaxBound. Bài đăng của bạn cần một số điều chỉnh.
mickmackusa

Có vẻ như tôi đã mắc lỗi chính tả trên các toán tử bình đẳng. Nắm bắt tốt.
LanchPad

0

Trong trường hợp này col BETWEEN ... AND ...col <= ... and col >= ...tương đương.


Tiêu chuẩn SQL cũng định nghĩa vị từ T461 Đối xứng GIỮA :

 <between predicate part 2> ::=
 [ NOT ] BETWEEN [ ASYMMETRIC | SYMMETRIC ]
 <row value predicand> AND <row value predicand>

Transact-SQL không hỗ trợ tính năng này.

BETWEENyêu cầu rằng các giá trị được sắp xếp. Ví dụ:

SELECT 1 WHERE 3 BETWEEN 10 AND 1
-- no rows

<=>

SELECT 1 WHERE 3 >= 10 AND 3 <= 1
-- no rows

Mặt khác:

SELECT 1 WHERE 3 BETWEEN SYMMETRIC 1 AND 10;
-- 1

SELECT 1 WHERE 3 BETWEEN SYMMETRIC 10 AND 1
-- 1

Nó hoạt động chính xác như bình thường BETWEENnhưng sau khi sắp xếp các giá trị so sánh.

db <> bản trình diễn fiddle

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.