SQL tarih ve saat fonksiyonları: dönem analizi için pratik rehber
Beceri rehberi

SQL tarih ve saat fonksiyonları: dönem analizi için pratik rehber

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

SQL'de tarih ve saat fonksiyonlarıyla gün farkı hesaplama, ay ve yıla göre gruplama, dönem başı bulma ve SQL Server, MySQL, PostgreSQL farkları.

Tarih fonksiyonları ne için kullanılır?

Satış, sipariş, ziyaret ya da destek talebi gibi iş verilerinin neredeyse hepsinde bir tarih alanı bulunur. Bu verilerden anlamlı rapor çıkarmak için tarihle şu işlemleri yapmak gerekir: bugünün tarihini almak, tarihten ay ya da yıl bilgisini ayıklamak, tarihler arasındaki farkı hesaplamak, tarihe gün ay eklemek ya da çıkarmak, kayıtları aya, çeyreğe ya da yıla göre gruplamak.

Tarih fonksiyonları veritabanı sistemleri arasında en çok farklılaşan SQL alanlarından biridir. Aynı işlem SQL Server'da bir fonksiyonla, MySQL'de ve PostgreSQL'de ise farklı biçimlerde yazılır. Bu yüzden tek bir sözdizimini ezberlemek yerine ne yapılmak istendiğini bilip kullandığınız sistemin karşılığını bulmak daha sağlam bir yaklaşımdır.

İşlemler mantık düzeyinde ele alınır; her sistemin tipik fonksiyon adları yanında verilir. Kullandığınız sürümün güncel belgesi her zaman son sözü söyler.

Bugünün tarihi, tarih parçaları ve tarih ekleme

Güncel tarih ve saati almak için SQL Server'da GETDATE, MySQL'de NOW, PostgreSQL'de NOW ya da CURRENT_DATE kullanılır. Raporlarda "son dönem" ya da "bu ay" gibi dinamik aralıklar bu fonksiyonlarla kurulur; sabit tarih yazmak raporun her gün elle güncellenmesini gerektirir.

Tarihten parça ayıklamak için YEAR, MONTH, DAY fonksiyonları SQL Server ve MySQL'de yaygındır; PostgreSQL'de bunun karşılığı EXTRACT ya da DATE_PART'tır. SQL Server'daki DATEPART ve DATENAME, haftanın günü ya da çeyrek gibi parçaları da verir. Sonuç sayı olarak gelir; ay adı gerekiyorsa ayrıca dönüştürülmelidir.

Tarihe gün, ay, yıl eklemek için SQL Server'da DATEADD, MySQL'de DATE_ADD, PostgreSQL'de INTERVAL ifadesi kullanılır. Örneğin sözleşme başlangıç tarihine belirli bir süre ekleyerek bitiş tarihini hesaplamak ya da bugünden belirli bir süre geriye gidip son dönem filtresi oluşturmak bu işlevlerle yapılır.

Dönem başı ve dönem sonu bulmak da sık gerekir. SQL Server'da EOMONTH ayın son gününü verir; PostgreSQL'deki DATE_TRUNC, tarihi ay, çeyrek ya da yıl başına yuvarlar. MySQL'de benzer sonuç için tarih biçimlendirme veya hesaplama gerekir.

Tarihler arasındaki farkı hesaplama

Gün, ay ya da yıl farkı için SQL Server'da DATEDIFF fonksiyonu kullanılır: hangi birimde (day, month, year) sayılacağı en baştaki argümanla verilir. MySQL'de DATEDIFF yalnızca gün farkı döner; ay ya da yıl için TIMESTAMPDIFF kullanılır. PostgreSQL'de tarihlerin birbirinden çıkarılması gün farkı verir, daha ayrıntılı ihtiyaç için AGE fonksiyonu kullanılır.

Bir tuzak: SQL Server'daki DATEDIFF, sınır geçişlerini sayar, geçen tam süreyi değil. Yani ayın son günü ile bir sonraki ayın başlangıç günü arasında ay birimiyle fark alınırsa sonuç bir ay görünür, oysa arada yalnızca bir gün vardır. Yaş ya da tam ay hesabı gibi hassas işlerde bu davranışı bilmek ve gerekirse ek kontrol eklemek şarttır.

Örnek bir kullanım: sipariş tarihi ile teslim tarihi arasındaki gün farkı bulunur, ortalama teslim süresi ve geciken sipariş oranı hesaplanır. Bu tür bir ölçü, lojistik performansı gibi operasyonel raporların temelini oluşturur.

Aya, çeyreğe, yıla göre dönem analizi

Dönem analizinin standart yolu, tarihi gruplama birimine indirip GROUP BY ile toplamaktır. Aylık satış raporu için tarih önce ay başına yuvarlanır (PostgreSQL'de DATE_TRUNC, SQL Server'da yıl ve ay parçalarının birlikte kullanılması gibi), sonra bu değere göre gruplanıp SUM alınır. Yıl ve ayı ayrı sütun olarak gruplamak da mümkündür, ancak tek bir dönem başı tarihi hem sıralamayı hem grafik eksenini kolaylaştırır.

Dönemleri karşılaştırmak için bir yöntem, aynı sorguda koşullu toplama kullanmaktır: bu ayın toplamı ve geçen ayın toplamı CASE WHEN ile yan yana alınır. Daha esnek bir yöntem, dönemlere göre toplamı aldıktan sonra LAG gibi pencere fonksiyonlarıyla önceki dönemi satır olarak getirmektir.

Dönem raporlarında eksik dönemler de sorun yaratır. Satış olmayan bir ay sonuçta hiç görünmez, çünkü o aya ait satır yoktur. Grafik süreklilik gerektiriyorsa ayrı bir takvim tablosu oluşturulup verilerle birleştirilir. Bu hem SQL hem Power BI gibi araçlarda standart bir uygulamadır.

Zaman damgası, saat dilimi ve biçimlendirme

Tarih alanı yalnızca gün değil saat de taşıyorsa, günlük gruplama yapılırken saat kısmı atılmalıdır. Aksi halde aynı günün farklı saatlerindeki kayıtlar ayrı gruplara düşer. SQL Server'da CAST ile tarih türüne çevirmek, PostgreSQL'de DATE_TRUNC ile gün birimine yuvarlamak bu iş için kullanılır.

Saat dilimi ayrı bir konudur. Veritabanı sunucusu bir saat diliminde, kullanıcılar başka birinde olabilir. Sistem tarihleri UTC olarak saklıyorsa, raporda yerel saate çevirmeden yapılan gün gruplaması gece yarısına yakın kayıtları yanlış güne yazabilir. Hangi saat diliminin esas alındığını başta belirlemek ve tüm raporlarda aynı kuralı uygulamak gerekir.

Biçimlendirme, yani tarihin ekranda nasıl görüneceği, mümkünse raporlama aracına bırakılmalıdır. SQL tarafında FORMAT, DATE_FORMAT ya da TO_CHAR gibi fonksiyonlar tarihi metne çevirir; metne çevrilen tarih ise doğru sıralanmaz ve tarih işlemlerine uygun olmaz. Hesaplamalar tarih türüyle, görüntüleme son adımda metinle yapılmalıdır.

Sık yapılan hatalar

En yaygın hata, tarih sütununu fonksiyonla sarıp filtrelemektir. WHERE YEAR(tarih) eşittir belirli bir yıl biçimindeki koşul, sütundaki indeksin kullanılmasını engelleyebilir ve büyük tablolarda yavaşlatır. Bunun yerine tarihin aralığı doğrudan karşılaştırılır: başlangıca eşit ya da büyük, bitişten küçük.

Bir başka yaygın hata, bitiş gününü dışarıda bırakmaktır. Saatli bir alanda "belirli gün ve öncesi" filtresi yazılırsa, o günün gün içindeki kayıtları gece yarısından sonra oldukları için eksik kalır. Çözüm: bitiş tarihi için bir sonraki günün başlangıcından küçük koşulu kullanmaktır.

Diğer hatalar: • Metin olarak saklanan tarihleri dönüştürmeden karşılaştırmak, alfabetik sıralamaya yol açar • DATEDIFF gibi fonksiyonların sınır sayma davranışını bilmemek • Saat dilimi farkını hesaba katmamak • Veritabanı sistemleri arasında fonksiyon adlarını birebir taşımaya çalışmak • Dönem karşılaştırmasında eksik dönemleri atlamak

Bu beceriyi Mindset programlarında nerede çalışırsınız?

Mindset kataloğundaki SQL ile Veri Sorgulama (Temel) eğitiminin Filtreleme Teknikleri ve Temel Fonksiyonlar, Toplulaştırma Fonksiyonları ve Gruplama ve Pratik İş Raporları ile Sorgu Geliştirme modülleri tarih alanlarıyla rapor sorguları geliştirmek isteyenler için ilgili başlıklardır.

SQL ile Programlama Eğitimi ise Hesaplamalar ile Toplama ve Gruplama başlıklarını içerir. Finans, satış operasyonları ve raporlama ekiplerinde dönemsel rapor hazırlayan çalışanlar bu başlıkları birlikte çalışabilir.

İlgili Mindset programı

SQL ile Veri Sorgulama (Temel)

Sık sorulanlar

Sık sorulan sorular

Tarih fonksiyonları tüm veritabanlarında aynı mı?

Hayır. Mantık aynıdır ama fonksiyon adları ve sözdizimi sistemden sisteme değişir. SQL Server'da DATEDIFF ve DATEADD, MySQL'de DATE_ADD ve TIMESTAMPDIFF, PostgreSQL'de ise INTERVAL ve DATE_TRUNC öne çıkar. Başka sistemden sorgu taşırken fonksiyonları kullandığınız sistemin belgesine göre uyarlamanız gerekir.

Aylık gruplamayı en doğru nasıl yaparım?

Tarihi ay başına indirip bu değere göre gruplamak en temiz yoldur: hem sıralama doğru olur hem de yıl ve ay tek sütunda taşınır. Yalnızca ay numarasına göre gruplamak farklı yılların aynı aylarını karıştırır. Bu yüzden ay numarasıyla birlikte yılı da gruplamaya almayı unutmayın.

Metin olarak tutulan tarihlerle nasıl çalışılır?

Önce tarih türüne dönüştürmek gerekir. CAST, CONVERT ya da TO_DATE gibi fonksiyonlar metni tarihe çevirir. Metin formatı tutarsızsa dönüşüm hata verebilir, bu yüzden önce veriyi temizlemek gerekir. Mümkünse tarihler kaynakta doğru türde saklanmalıdır; metin olarak tutmak sıralama ve filtreleme sorunlarına yol açar.

Yaş veya kıdem süresi SQL'de nasıl hesaplanır?

Gün farkından yıla bölmek hatalıdır, çünkü artık yıllar gözden kaçar. SQL Server'da DATEDIFF yıl birimi sınır saydığından doğum günü geçmemişse bir fazla verebilir; bu durumu kontrol eden ek koşul gerekir. PostgreSQL'de AGE fonksiyonu tam yıl hesabı için daha uygundur. Sonucu birkaç örnek tarihle sınamak iyi uygulamadır.

Tarih filtrelerinde sorgu neden yavaşlar?

Genellikle tarih sütunu bir fonksiyonla sarıldığı için indeks kullanılamaz. Bunun yerine sütunu olduğu gibi bırakıp aralık koşulu yazmak gerekir. Ayrıca sorgulanan tarih sütununda indeks bulunması, filtre sonrası gruplamanın hızlı çalışması için önemlidir. Çok büyük tablolarda tarihe göre bölümleme de değerlendirilebilir.

SQL Tarih Fonksiyonları: Dönem Analizi Nasıl Yapılır?