Tarih Aralığına Göre Filtreleme: BETWEEN Mi, Büyüktür ve Küçüktür Mü?
Beceri rehberi

Tarih Aralığına Göre Filtreleme: BETWEEN Mi, Büyüktür ve Küçüktür Mü?

Hazırlayan: Mindset Institute EditörlüğüGüncellendi: 5 dk okuma

İki tarih arasındaki kayıtlar BETWEEN ile neden eksik gelebilir? Saat bilgisi, alt sınır dahil üst sınır hariç kalıbı, indeks ve biçim tuzakları anlatılır.

Tarih aralığı filtresi neden hata yapmaya açıktır?

Belirli bir dönemin kayıtlarını getirmek en sık yazılan sorgulardan biridir: bu ayın siparişleri, geçen haftanın girişleri, belirli bir kampanya dönemindeki satışlar. Sorgu basit görünür ama sonuçta sessizce eksik ya da fazla satır gelmesi çok yaygındır. Çünkü hata mesajı vermez, yalnızca raporu yanlış yapar.

Sorunların kaynağı birkaç yerde toplanır: tarih ile saat bilgisinin birlikte saklandığı sütunlarda sınır değerlerin yanlış yorumlanması, tarih biçimi ve yerel ayar farkları ve filtrenin sütuna fonksiyon uygulayarak yazılması nedeniyle indeksin kullanılamaması.

Bu konuda öğrenilecek tek kural şudur: aralığı alt sınır dahil, üst sınır hariç olacak biçimde kurun. Bu kalıp saat bilgisi olsun olmasın, sistem hangisi olursa olsun doğru sonuç verir.

BETWEEN nasıl çalışır?

BETWEEN, bir değerin alt ve üst sınır arasında olup olmadığını denetler ve alt ve üst sınırı da dahil eder. WHERE siparis_tarihi BETWEEN baslangic AND bitis ifadesi, siparis_tarihi >= baslangic AND siparis_tarihi <= bitis ifadesiyle birebir aynıdır. Bu yüzden sınırların ikisi de sonuca dahildir.

Sütunun yalnızca tarih (saat içermeyen) türünde olduğu durumlarda BETWEEN sorunsuz çalışır. Başlangıç ve bitiş günü dahil edilir ve sonuç beklenen gibidir. Sınır değerlerini ise sisteme göre tarih sabiti olarak vermeniz gerekir; ISO biçimi (yıl-ay-gün) hemen her sistemde güvenle anlaşılır.

BETWEEN'in küçük bir tuzağı, sınırların sırasıdır: küçük değer önce, büyük değer sonra yazılmalıdır. Sırayı ters yazarsanız çoğu sistem hata vermez, ancak hiçbir satır dönmez. Parametreyle çalışan uygulamalarda başlangıç tarihinin bitişten büyük gelme ihtimalini ayrıca kontrol etmek gerekir.

Saat bilgisi olan sütunlarda BETWEEN neden eksik sonuç verir?

Sütun zaman damgası (DATETIME, TIMESTAMP) türündeyse her değer günün içinde bir ana karşılık gelir. Bitiş sınırı olarak yalnızca tarih verdiğinizde sistem bunu o günün gece yarısı, yani başlangıcı olarak yorumlar. O günün öğleden sonrasındaki kayıtlar, sınırı geçtikleri için sonuca girmez.

Örneğin ayın son gününü bitiş olarak yazdınız. Ayın son günü saat farkıyla gelen siparişler eksik kalır; rapor tutarı sessizce düşük çıkar. Bu, tarih aralığı sorgularındaki en yaygın hatadır.

Bitişe günün son saniyesini yazmak bir çözüm gibi görünür, ancak kırılgandır. Sütunun hassasiyeti saniyenin kesirlerini içeriyorsa, günün son saniyesinden sonraki anlar yine dışarıda kalır. Üstelik sistemlerin zaman türlerini yuvarlama biçimi farklıdır.

Doğru çözüm, bitiş günü için bir sonraki günün başlangıcını üst sınır olarak alıp küçüktür işaretini kullanmaktır.

Doğru kalıp: alt sınır dahil, üst sınır hariç

Kalıp şöyle yazılır: WHERE siparis_tarihi >= baslangic AND siparis_tarihi < bitis_ertesi_gun. Başlangıç, dönemin ilk günü gece yarısıdır; üst sınır, dönemin son gününün ertesi günü gece yarısıdır ve bu değer sonuca dahil olmaz. Böylece son günün her saati, saniye altı değerleri dahil, doğru biçimde kapsanır.

Bu yaklaşımın avantajları: • Sütun tarih ya da zaman damgası olsun, aynı kalıp çalışır. • Saat hassasiyetinden bağımsızdır. • Dönemler arka arkaya dizildiğinde bir önceki dönemin üst sınırı sonrakinin alt sınırıyla aynı olur; hiçbir kayıt birden fazla dönemde sayılmaz ve boşluk kalmaz. • İndeks kullanımına uygundur.

Üst sınırı elle hesaplamak yerine tarih fonksiyonlarını kullanabilirsiniz: SQL Server'da DATEADD, MySQL'de DATE_ADD ya da INTERVAL, PostgreSQL'de INTERVAL ile tarih aritmetiği. Fonksiyon adları sisteme göre değişir, kullandığınız sistemin dokümantasyonuna bakın. Ay bazlı raporlarda ayın ilk gününü ve bir sonraki ayın ilk gününü sınır olarak almak, ayın kaç gün çektiğini bilme ihtiyacını da ortadan kaldırır.

Göreli aralıklar: bu ay, geçen hafta, son günler

Raporlar çoğu zaman sabit tarihler yerine göreli aralıklara dayanır. Bunun için sistemin bugünün tarihini veren fonksiyonu (CURRENT_DATE, GETDATE ya da NOW türü fonksiyonlar) ve tarih aritmetiği kullanılır. Mantık aynıdır: dönemin başlangıcı ve bir sonraki dönemin başlangıcı hesaplanır, filtre alt sınır dahil üst sınır hariç yazılır.

Örneğin bu ayın kayıtları için ayın ilk gününü bulmanız gerekir. Bunu yapan fonksiyonlar sisteme göre değişir; SQL Server'da DATEFROMPARTS ya da DATEADD ile DATEDIFF birleşimi, PostgreSQL'de DATE_TRUNC, MySQL'de tarih biçimlendirme fonksiyonları kullanılabilir. Son belirli gün için bugünden geriye doğru bir aralık çıkarılır.

Bu hesabı sorgu içinde yapmak yerine parametre olarak uygulamadan göndermek de olasıdır. Hangi saat dilimine göre bugünün hesaplandığına dikkat edin: sunucu saat dilimi ile kullanıcının saat dilimi farklıysa gece yarısına yakın kayıtlar yanlış güne düşebilir. Zaman damgalarını UTC olarak saklayan sistemlerde bu konu özellikle önemlidir.

Sık yapılan hatalar: fonksiyon, biçim ve indeks

Başlıca hatalar şunlardır: • Sütuna fonksiyon uygulamak: WHERE DATE(siparis_tarihi) = belirli gün ya da YEAR(siparis_tarihi) gibi ifadeler her satıra fonksiyon çalıştırır ve sütundaki indeksin kullanımını engeller. Aynı sonucu aralık koşuluyla almak çok daha hızlıdır. • Tarihi metin gibi karşılaştırmak: tarih sütununu metinle karşılaştırırsanız örtük dönüşüm hata yapabilir ya da indeksi kullanamaz. Sabiti tarih türünde verin. • Yerel biçimle yazmak: gün-ay-yıl biçimi bazı sistem ve dil ayarlarında ay-gün-yıl olarak okunur. ISO biçimi, yıl önde olacak şekilde yazılır, belirsizliği ortadan kaldırır. • BETWEEN'de ters sıra: hiçbir kayıt dönmez. • NULL tarihler: filtrede NULL değerli satırlar sonuca girmez; boş tarihli kayıtları ayrıca düşünün. • Saat dilimini ihmal etmek.

Bu konular, SQL ile Veri Sorgulama (Temel) eğitiminin Filtreleme Teknikleri ve Temel Fonksiyonlar modülünün parçasıdır; SQL ile Programlama Eğitimi ise Sorgular ve Hesaplamalar modüllerini içerir. Bu içerikler, dönemsel satış ve operasyon raporu hazırlayan analist ve finans ekipleri için uygundur.

İlgili Mindset programı

SQL ile Veri Sorgulama (Temel)

Sık sorulanlar

Sık sorulan sorular

BETWEEN başlangıç ve bitiş tarihini dahil eder mi?

Evet, BETWEEN alt ve üst sınırı da dahil eder. Ancak sütun saat bilgisi içeriyorsa bitiş olarak verdiğiniz tarih o günün başlangıcı sayılır ve gün içindeki kayıtlar sonuca girmez. Bu yüzden zaman damgası sütunlarında alt sınır dahil, üst sınır hariç kalıbı güvenlidir.

Son günün tüm kayıtlarını eksiksiz almak için ne yazmalıyım?

Bitiş koşulunu son günün ertesi günü olacak biçimde küçüktür işaretiyle yazın: tarih >= başlangıç AND tarih < bitişin ertesi günü. Bu sayede o günün her saati ve saniye altı değerler dahil olur. Bitişe gün sonu saati yazmak kırılgan bir yöntemdir.

Tarih biçimi nedeniyle yanlış sonuç alabilir miyim?

Evet. Gün-ay-yıl yazımı bazı sistem ve dil ayarlarında ay-gün-yıl gibi farklı yorumlanabilir. Yıl önde olacak şekilde ISO biçimi (yıl-ay-gün) her yerde aynı anlaşılır ve belirsizliği ortadan kaldırır. Mümkünse tarihleri uygulamadan parametre olarak, tarih türünde gönderin.

Tarih sütununda indeks varken sorgu neden yavaş?

Büyük olasılıkla sütuna fonksiyon uygulanıyordur; örneğin YEAR veya DATE fonksiyonu indeksin kullanımını engeller. Filtreyi sütunu dönüştürmeden, doğrudan aralık koşuluyla yazın. Yürütme planında indeks taramasının mı yoksa tablo taramasının mı yapıldığını kontrol edin.

Haftalık ya da aylık gruplama için aynı mantığı kullanabilir miyim?

Filtre için evet; dönemin başı ve bir sonraki dönemin başı sınır olur. Gruplama için ise sistemin tarih kısaltma fonksiyonları kullanılır, örneğin PostgreSQL'de DATE_TRUNC. Filtreyi aralık koşuluyla, gruplamayı fonksiyonla yapmak hem doğru hem verimli bir birleşimdir.

SQL'de Tarih Aralığı Filtreleme: BETWEEN Tuzakları