Klausa “antara” MySQL tidak termasuk?

142

Jika saya menjalankan kueri dengan betweenklausa, sepertinya mengecualikan nilai akhir.
Sebagai contoh:

select * from person where dob between '2011-01-01' and '2011-01-31'

Ini mendapatkan semua hasil dobdari '2011-01-01' hingga '2011-01-30'; melewatkan catatan di mana dob'2011-01-31'. Adakah yang bisa menjelaskan mengapa kueri ini berperilaku seperti ini, dan bagaimana saya bisa memodifikasinya untuk memasukkan catatan di mana dob'2011-01-31'? (tanpa menambahkan 1 ke tanggal berakhir karena telah dipilih oleh pengguna.)

ASD
sumber
Nggak. Apakah instalasi MySQL saya (versi?) BETWEENInklusif untuk kedua nilai. Saya miliki MySQL Server 5.7di Windows 10.
Green

Jawaban:

181

Bidang dobmungkin memiliki komponen waktu.

Untuk memotongnya:

select * from person 
where CAST(dob AS DATE) between '2011-01-01' and '2011-01-31'
tiago2014
sumber
59
Alih-alih CAST(dob AS DATE)Anda bisa menggunakan yang lebih ringkas DATE(dob).
jkndrkn
11
Saat ini berfungsi, Anda akan mendapatkan kinerja yang lebih baik dengan menggunakan >=dan <bukannya between.
David Harkness
112
Anda akan mendapatkan kinerja yang lebih baik dengan menggunakan dob BETWEEN '2011-01-01 00:00:00' AND '2011-01-31 23:59:59. Ini karena DATE(dob)harus menghitung nilai untuk setiap baris dan tidak dapat menggunakan indeks apa pun di bidang itu.
joshuahedlund
2
@ joshuahedlund Silakan tambahkan jawaban dengan solusi ini. CAST hampir tidak efisien.
doc_id
3
@ joshuahedlund Itu berfungsi sampai Anda memiliki data dengan waktu t > 23:59:59 and t < 24:00:00. Mengapa berurusan dengan yang tidak ditentukan BETWEENsama sekali? Sebaliknya mengikuti saran David dan penggunaan: WHERE dob >= '2011-01-01' AND dob < '2011-02-01'. Performa terbaik, dan ini bekerja setiap saat.
Disillusioned
300

Dari manual-MySQL :

Ini sama dengan ekspresi (min <= expr DAN expr <= maks)

Frank Heikens
sumber
3
Manual yang ditautkan dalam jawaban ini menunjukkan bahwa para pemain lebih disukai ketika membandingkan objek DATE dan DATETIME. Jadi saya kira @tiagoinu memiliki jawaban paling lengkap dalam arti paling ketat, tetapi keduanya tepat.
Kingsolmn
@jemminger mungkin karena jawabannya adalah dari archrival -postgres guy: P
nawfal
27
Singkatnya inklusif ... itu sebabnya jawaban ini mengguncang.
Rafael
6
Komentar lama, tapi saya ingin mengikat ini dengan permintaan khusus. "BETWEEN" inklusif, tetapi tanggal tanpa pad waktu yang ditentukan hingga 00:00:00. Karena itu, membandingkan pada rentang tanggal akan kehilangan hari terakhir. Panggil DATE (dob) atau tentukan akhir hari.
wintermute92
mereka mengatakan latihan adalah emas, dari kasus penggunaan saya itu tidak inklusif sama sekali, saya bertanya-tanya mengapa ini terjadi pada saya. Saya mencoba dan kadang-kadang berhasil kadang tidak. menggunakannya pada bidang data TIME.
Jeffery ThaGintoki
99

Masalahnya adalah 2011-01-31 benar-benar 2011-01-31 00:00:00. Itulah awal dari hari itu. Semuanya siang hari tidak termasuk.

Daniel Hilgarth
sumber
19
Ini benar-benar menjelaskan apa yang sedang terjadi dan menjawab pertanyaan itu.
Ivan P
3
Bagaimanapun juga, jawaban ini masih yang terbaik. Terima kasih banyak.
Strabek
31
select * from person where dob between '2011-01-01 00:00:00' and '2011-01-31 23:59:59'
Gaurav
sumber
1
Saya pikir itu perlu dicatat bahwa, ini tidak akan termasuk tanggal 2011-01-31 23:59:59tetapi akan mencakup mereka sampai 2011-01-31 23:59:58 detik terakhir hari ini tidak termasuk. Ini mungkin kecil tetapi seseorang akan mendapat manfaatnya.
doc_id
1
rahmanisback dari Dokumentasi MySQL Saya dapat mengkonfirmasi detik terakhir AKAN dimasukkan karena BETWEEN termasuk dalam dua-cara. lihat dev.mysql.com/doc/refman/5.5/en/…
Felype
1
Ya, @Felype Anda benar. Saya memeriksa ini sendiri di database mysql. Ini termasuk juga 23:59:59dalam hasilnya. Jadi keduanya inklusif.
Lucky
2
Jika dobkolom adalah stempel waktu dengan ketepatan kedua, maka BETWEENtetap tidak akan melewatkan acara dalam detik terakhir kecuali jika '2011-02-01 00:00:00' digunakan sebagai gantinya?
nitrogen
1
-1. Tidak akan termasuk 2011-01-31 23:59:59.003. @nitrogen menggunakan 2011-02-01 000:00:00akan salah memasukkan nol waktu pada tanggal 1 Februari .... Itulah sebabnya >=dan <harus digunakan sebagai gantinya.
Disillusioned
6

Apakah lapangan Anda referensi dalam permintaan Anda sebuah Tanggal jenis atau DateTime jenis?

Penyebab umum perilaku yang Anda gambarkan adalah ketika Anda menggunakan tipe DateTime di mana Anda seharusnya menggunakan tipe Date. Yaitu, kecuali Anda benar-benar perlu tahu jam berapa seseorang dilahirkan, cukup gunakan jenis Tanggal.

Alasan hari terakhir tidak dimasukkan dalam hasil Anda adalah cara kueri mengasumsikan bagian waktu dari tanggal yang tidak Anda tentukan dalam kueri Anda.

Yaitu: Kueri Anda sedang ditafsirkan hingga Tengah malam antara 2011-01-30 dan 2011-01-31, tetapi data mungkin memiliki nilai beberapa saat kemudian pada hari 2011-01-31.

Saran: Ubah bidang ke tipe Tanggal jika ini adalah tipe DateTime.

JohnFx
sumber
4

Hai kueri ini berfungsi untuk saya,

select * from person where dob between '2011-01-01' and '2011-01-31 23:59:59'
infinito84
sumber
2
select * from person where DATE(dob) between '2011-01-01' and '2011-01-31'

Konversi seperti itu adalah solusi untuk banyak masalah di MySQL.

betty.88
sumber
10
Anehnya, inilah jawaban yang diterima (dan beberapa yang lain) katakan ... 2 tahun sebelum Anda melakukannya.
Chris Baker
0

Tetapkan tanggal atas ke tanggal + 1 hari, jadi dalam kasus Anda, atur ke 2011-02-01.

Rafal
sumber
1
Ini akan salah memasukkan nol waktu pada tanggal 1 Februari .... Itulah sebabnya mengapa BETWEENharus diabaikan; tetapi >=dan <harus digunakan sebagai gantinya.
Disillusioned
0

Anda dapat menjalankan kueri sebagai:

select * from person where dob between '2011-01-01' and '2011-01-31 23:59:59'

seperti yang ditunjukkan orang lain, jika teman kencan Anda dikodekan dengan keras.

Di sisi lain, jika tanggal ada di tabel lain, Anda dapat menambahkan satu hari dan mengurangi satu detik (jika tanggal disimpan tanpa yang kedua kali), seperti:

select * from person JOIN some_table ... where dob between some_table.initial_date and (some_table.final_date + INTERVAL 1 DAY - INTERVAL 1 SECOND)

Hindari melakukan gips di lapangan dob(seperti dalam jawaban yang diterima), karena itu dapat menyebabkan masalah kinerja yang sangat besar (seperti tidak dapat menggunakan indeks di doblapangan, dengan asumsi ada satu). Rencana eksekusi dapat berubah dari using index conditionmenjadi using wherejika Anda membuat sesuatu seperti DATE(dob)atauCAST(dob AS DATE) , jadi berhati-hatilah!

Lucas Basquerotto
sumber
0

Karena itu, di MySql, nilai-nilai tersebut inklusif saat Anda mencoba untuk mendapatkan antara '2011-01-01' dan '2011-01-31'

itu akan mencakup dari 2011-01-01 00:00:00upto2011-01-31 00:00:00 karena itu tidak ada benar-benar dalam 2011-01-31 sejak waktu harus pergi dari2011-01-31 00:00:00 ~ 2011-01-31 23:59:59

Untuk batas atas, Anda dapat mengubah 2011-02-01lalu mendapatkan semua data hingga2011-01-31 23:59:59

Ambleu
sumber