SQL: BETWEEN เทียบกับ <= และ> =


111

ใน SQL Server 2000 และ 2005:

  • อะไรคือความแตกต่างระหว่างสองWHEREข้อนี้?
  • ฉันควรใช้กับสถานการณ์ใด

คำค้นหา 1:

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

แบบสอบถาม 2:

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

(แก้ไข: Eventdate ที่สองเดิมหายไปดังนั้นแบบสอบถามจึงผิดทางไวยากรณ์)


1
นี่คือการจำลองเสมือนกับstackoverflow.com/questions/1572840/sql-between-v1-and-v2
mjv

6
ไม่จริงการจัดการ datetime แตกต่างกันเล็กน้อยบวกกับ SQL Server 2008 และไม่มีทางที่ Shyju จะมั่นใจได้โดยไม่ต้องถามว่าคำตอบจะเหมือนกันสำหรับเวอร์ชันก่อนหน้า
Irfy

คำตอบ:


119

เหมือนกัน: BETWEENเป็นชวเลขสำหรับไวยากรณ์ที่ยาวกว่าในคำถาม

ใช้ไวยากรณ์ทางเลือกที่ยาวกว่าซึ่งใช้BETWEENไม่ได้เช่น

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

(หมายเหตุ<แทนที่จะ<=อยู่ในเงื่อนไขที่สอง)


19
บางทีคุณควรเน้นจุดที่เงื่อนไขที่สองคือ '<' ฉันใช้เวลาพอสมควรในการมองเห็นความแตกต่าง
zendar

21
ฉันขอเพิ่มว่าฉันขอแนะนำอย่างยิ่งว่าอย่าใช้ BETWEEN เว้นแต่คุณจะจัดการกับประเภทข้อมูล DATE หรือรับประกันเป็นอย่างอื่นว่าค่าวันที่และเวลาของคุณจะไม่มีองค์ประกอบเวลา การมีความสอดคล้องกันจะทำให้มีโอกาสน้อยที่คุณจะใช้ BETWEEN โดยไม่ได้ตั้งใจแทนที่จะเป็น> = และ <และอาจได้รับข้อมูลบางอย่างในแบบสอบถามที่คุณไม่ได้ตั้งใจหรือคิดว่าคุณจะได้รับวันเพิ่มเติม ข้อมูลเมื่อคุณไม่ ...
Aaron Bertrand

1
จะมีขั้นตอนคอมไพเลอร์ที่สองเนื่องจาก BETWEEN ถูกแปลงเป็นเงื่อนไขหรือไม่? ฉันเข้าใจว่านี่เป็นการอวดดีเล็กน้อย แต่จะมีค่าใช้จ่ายเพิ่มเติมหรือไม่?
James Scott

1
@xmashallax เพราะพวกเขา? พวกเขาไม่ได้อย่างไร?
Tony Andrews

2
แปลก ... ฉันคิดว่าฉันสับสนกับคำถามการเขียนคำตอบความคิดเห็นและความจริงที่ว่าตอนนี้รหัสของฉันมีข้อผิดพลาดอย่างเห็นได้ชัด =)
xmashallax

37

พวกเขาก็เหมือน ๆ กัน.

สิ่งหนึ่งที่ควรระวังคือหากคุณใช้สิ่งนี้กับ DATETIME การจับคู่สำหรับวันที่สิ้นสุดจะเป็นจุดเริ่มต้นของวัน:

<= 20/10/2009

ไม่เหมือนกับ:

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

(มันจะตรงกับ<= 20/10/2009 00:00:00.000)


คุณสามารถใช้ระหว่าง '2009-10-20' และ '2009-10-21' ในกรณีนั้นเพื่อจับภาพวันนี้
David Andrei Ned

4
@DavidAndreiNed ที่จะตรงกับ '2009-10-21 00: 00: 00.000' - อาจไม่ใช่สิ่งที่คุณต้องการ
Hans Ke st ing

2
คุณต้องการฟิลด์ระหว่าง '2009-10-20 00:00:00' และ '2009-10-20 23:59:59' หรือฟิลด์> = '2009-10-20 00:00:00' และฟิลด์ <= '2009-10-20 23:59:59' เป็นที่แน่นอน
geilt

@geilt ตัวอย่างของคุณจะพลาดสิ่งที่เกิดขึ้นภายในวินาทีสุดท้ายของวัน ... กล่าวคือในระหว่าง 23:59:59 น. ถึง 00:00:00 น. ของวันถัดไป
Seth Flowers

00:00:00 เป็นวันเริ่มต้นของวันถัดไปและทำไมฉันถึงใช้> = และ <= และไม่ใช่> หรือ <แต่ถ้าคุณหมายถึงไมโครวินาทีและคุณเก็บไว้คุณก็ต้องใส่ไมโครวินาทีสุดท้ายและสุดท้ายด้วยเช่นกัน
geilt

14

แม้ว่าBETWEENจะอ่านและดูแลรักษาง่าย แต่ฉันไม่ค่อยแนะนำให้ใช้เนื่องจากเป็นช่วงปิดและตามที่กล่าวไว้ก่อนหน้านี้อาจเป็นปัญหากับวันที่ - แม้จะไม่มีส่วนประกอบของเวลาก็ตาม

ตัวอย่างเช่นเมื่อจัดการกับข้อมูลรายเดือนมักเป็นเรื่องปกติที่จะเปรียบเทียบวันที่BETWEEN first AND lastแต่ในทางปฏิบัติมักจะเขียนได้ง่ายกว่าdt >= first AND dt < next-first(ซึ่งช่วยแก้ปัญหาส่วนเวลาได้เช่นกัน) เนื่องจากการกำหนดlastโดยปกติจะนานกว่าการกำหนดหนึ่งขั้นตอนnext-first(โดยการลบวัน) .

นอกจากนี้ gotcha อีกอย่างหนึ่งก็คือขอบเขตล่างและบนจะต้องระบุตามลำดับที่ถูกต้อง (เช่นBETWEEN low AND high)


4

โดยทั่วไปแล้วไม่มีความแตกต่าง - BETWEENไม่รองรับคีย์เวิร์ดบนแพลตฟอร์ม RDBMS ทั้งหมด แต่ถ้าเป็นเช่นนั้นคำค้นหาทั้งสองควรจะเหมือนกัน

เนื่องจากมันเหมือนกันจึงไม่มีความแตกต่างในแง่ของความเร็วหรือสิ่งอื่นใด - ใช้สิ่งที่ดูเหมือนเป็นธรรมชาติสำหรับคุณมากกว่า


4

ดังกล่าวโดย @marc_s, @Cloud, et al. โดยพื้นฐานแล้วจะเหมือนกันสำหรับช่วงปิด

แต่ค่าของเวลาใด ๆ ที่เป็นเศษส่วนอาจทำให้เกิดปัญหากับช่วงปิด (มากขึ้นหรือเท่ากันและน้อยกว่าหรือเท่ากับ ) เมื่อเทียบกับช่วงครึ่งเปิด (มากขึ้นหรือเท่ากันและน้อยกว่า ) ที่มีค่าสิ้นหลังจากสุดท้ายที่เป็นไปได้ทันที

ดังนั้นเพื่อหลีกเลี่ยงไม่ให้ข้อความค้นหาถูกเขียนใหม่เป็น:

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

เนื่องจากBETWEENไม่ทำงานในช่วงครึ่งเปิดฉันจึงมักจะตรวจสอบการสืบค้นวันที่ / เวลาใด ๆ ที่ใช้มันอย่างหนักเนื่องจากอาจเป็นข้อผิดพลาด


4

ฉันมีการตั้งค่าเล็กน้อยBETWEENเพราะมันทำให้มันทันทีที่ชัดเจนให้กับผู้อ่านที่คุณกำลังตรวจสอบข้อมูลหนึ่งสำหรับช่วง โดยเฉพาะอย่างยิ่งถ้าคุณมีชื่อฟิลด์ที่คล้ายกันในตารางของคุณ

ถ้าพูดตารางของเรามีทั้ง a transactiondateและ a transitiondateถ้าฉันอ่าน

transactiondate between ...

ฉันรู้ทันทีว่าปลายทั้งสองข้างของการทดสอบเทียบกับสนามนี้

ถ้าฉันอ่าน

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

ฉันต้องใช้เวลาสักครู่เพื่อให้แน่ใจว่าทั้งสองช่องเหมือนกัน

นอกจากนี้เมื่อข้อความค้นหาถูกแก้ไขเมื่อเวลาผ่านไปโปรแกรมเมอร์ที่เลอะเทอะอาจแยกสองฟิลด์ ฉันเคยเห็นข้อความค้นหามากมายที่บอกว่าชอบ

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

หากพวกเขาลองใช้ a BETWEENแน่นอนว่ามันจะเป็นข้อผิดพลาดทางไวยากรณ์และได้รับการแก้ไขทันที


3

ฉันคิดว่าความแตกต่างเพียงอย่างเดียวคือปริมาณของน้ำตาลสังเคราะห์ในแต่ละแบบสอบถาม BETWEEN เป็นเพียงวิธีที่เรียบง่ายในการพูดเหมือนกับคำถามที่สอง

อาจมีความแตกต่างเฉพาะ RDBMS บางอย่างที่ฉันไม่ทราบ แต่ฉันไม่คิดอย่างนั้นจริงๆ


2

เหตุผลไม่มีความแตกต่างเลย ประสิทธิภาพที่ชาญฉลาดมีอยู่ใน DBMS ส่วนใหญ่ - ไม่มีความแตกต่างเลย


2

ดูบล็อกโพสต์ที่ยอดเยี่ยมนี้จากAaron Bertrandเกี่ยวกับเหตุผลที่คุณควรเปลี่ยนรูปแบบสตริงของคุณและวิธีจัดการค่าขอบเขตในข้อความค้นหาช่วงวันที่


1
ลิงก์ย้ายมาที่นี่
João Ciocca

1

ข้อจำกัดความรับผิดชอบ: ทุกอย่างด้านล่างเป็นเพียงเรื่องเล็กน้อยและดึงมาจากประสบการณ์ส่วนตัวของฉันโดยตรง ใครก็ตามที่รู้สึกว่าต้องทำการวิเคราะห์เชิงประจักษ์อย่างเข้มงวดมากขึ้นสามารถดำเนินการได้และลงคะแนนถ้าฉัน ฉันทราบด้วยว่า SQL เป็นภาษาที่เปิดเผยและคุณไม่ควรต้องพิจารณาว่าโค้ดของคุณได้รับการประมวลผลอย่างไรเมื่อคุณเขียน แต่เพราะฉันให้ความสำคัญกับเวลาของฉันฉันจึงทำ

มีงบเทียบเท่าตรรกะที่ไม่มีที่สิ้นสุด แต่ฉันจะพิจารณาสาม (ish)

กรณีที่ 1: การเปรียบเทียบสองรายการในลำดับมาตรฐาน (แก้ไขลำดับการประเมินผล)

A> = MinBound และ A <= MaxBound

กรณีที่ 2: น้ำตาลสังเคราะห์ (ผู้เขียนไม่ได้เลือกลำดับการประเมิน)

ระหว่าง MinBound และ MaxBound

กรณีที่ 3: การเปรียบเทียบสองรายการตามลำดับการศึกษา (ลำดับการประเมินที่เลือกในเวลาเขียน)

A> = MinBound และ A <= MaxBound

หรือ

A <= MaxBound และ A> = MinBound

จากประสบการณ์ของฉันกรณีที่ 1 และกรณีที่ 2 ไม่มีความแตกต่างที่สอดคล้องกันหรือโดดเด่นในด้านประสิทธิภาพเนื่องจากเป็นเรื่องที่ไม่รู้

อย่างไรก็ตามกรณีที่ 3 สามารถปรับปรุงเวลาในการดำเนินการได้อย่างมาก โดยเฉพาะอย่างยิ่งหากคุณกำลังทำงานกับชุดข้อมูลขนาดใหญ่และมีความรู้เกี่ยวกับฮิวริสติกบางอย่างเกี่ยวกับว่าAมีแนวโน้มที่จะมากกว่าMaxBoundหรือน้อยกว่าMinBoundคุณสามารถปรับปรุงเวลาในการดำเนินการได้อย่างเห็นได้ชัดโดยใช้กรณีที่ 3 และสั่งการเปรียบเทียบ ตามนั้น

กรณีการใช้งานหนึ่งที่ฉันมีคือการค้นหาชุดข้อมูลในอดีตขนาดใหญ่ที่มีวันที่ที่ไม่ได้จัดทำดัชนีสำหรับระเบียนภายในช่วงเวลาที่กำหนด เมื่อเขียนแบบสอบถามฉันจะมีความคิดที่ดีว่ามีข้อมูลมากกว่านี้หรือไม่ก่อนช่วงเวลาที่กำหนดหรือหลังจากช่วงเวลาที่ระบุและสามารถสั่งการเปรียบเทียบของฉันได้ตามนั้น ฉันมีเวลาในการดำเนินการลดลงมากถึงครึ่งหนึ่งขึ้นอยู่กับขนาดของชุดข้อมูลความซับซ้อนของแบบสอบถามและจำนวนระเบียนที่กรองโดยการเปรียบเทียบครั้งแรก


อืมอะไรนะ? กรณีที่ 3 ไม่ใช้ตรรกะเดียวกันกับกรณีที่ 1 และกรณีที่ 2 หากคุณต้องการดูว่าAมีค่ามากกว่าขอบเขตทั้งสองหรือไม่ให้ตรวจสอบว่าค่าAนั้นมากกว่าMaxBoundหรือไม่ โพสต์ของคุณต้องมีการปรับเปลี่ยน
mickmackusa

ดูเหมือนว่าฉันจะพิมพ์ผิดเกี่ยวกับตัวดำเนินการความเท่าเทียมกัน จับดี.
LanchPad

0

ในสถานการณ์นี้col BETWEEN ... AND ...และcol <= ... and col >= ...เทียบเท่า


SQL Standard ยังกำหนดเพรดิเคตแบบสมมาตรระหว่าง T461 ด้วย :

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

Transact-SQL ไม่รองรับคุณสมบัตินี้

BETWEENต้องการให้เรียงลำดับค่า ตัวอย่างเช่น:

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

<=>

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

ในทางกลับกัน:

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

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

ทำงานได้ตามปกติBETWEENแต่หลังจากเรียงลำดับค่าการเปรียบเทียบแล้ว

db <> การสาธิตซอ

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.