Bir mesaj tablosundan günlük veya saatlik kayıt sayısı çıkarmak için ayrı sayaç tutmak zorunda değilsiniz. Önce hangi zaman aralığını raporladığınızı belirleyip satırları sınırlandırın, ardından istenen zaman dilimine göre gruplayın. Aşağıdaki örneklerde tablo ChatMaster, tarih sütunu start_date olarak korunmuştur; isimleri kendi şemanıza uyarlayın.
Günlük kayıt sayısı
start_date bir DATETIME veya TIMESTAMP sütunu olmalıdır. Tarih ve saatin birlikte tutulması bir hata değildir. Örnekteki Eylül 2018 aralığı yalnız örnek veridir.
SELECT DATE(start_date) AS gun, COUNT(*) AS adet
FROM ChatMaster
WHERE start_date >= '2018-09-01 00:00:00'
AND start_date < '2018-10-01 00:00:00'
GROUP BY DATE(start_date)
ORDER BY gun;
Alt sınır dahil, üst sınır hariçtir. Böylece son günün 23:59:59.123456 gibi kesirli saniyeleri dışarıda kalmaz. DATE() yalnız gruplama için tarih bölümünü alır; filtrede asıl sütun üzerinde aralık kullanılır. Fonksiyonların davranışı için MySQL tarih/zaman belgesine bakabilirsiniz.
Tek günün saatlik dağılımı
SELECT HOUR(start_date) AS saat, COUNT(*) AS adet
FROM ChatMaster
WHERE start_date >= '2018-09-11 00:00:00'
AND start_date < '2018-09-12 00:00:00'
GROUP BY HOUR(start_date)
ORDER BY saat;
Bu sorgunun aralığı tek gündür. Birkaç günü birlikte filtreleyip yalnız HOUR() ile gruplarsanız bütün günlerin aynı saatlerini toplarsınız. Her güne ait saatlik satır gerekiyorsa gün ve saati birlikte gruplamak gerekir:
SELECT DATE(start_date) AS gun,
HOUR(start_date) AS saat,
COUNT(*) AS adet
FROM ChatMaster
WHERE start_date >= '2018-09-01 00:00:00'
AND start_date < '2018-10-01 00:00:00'
GROUP BY DATE(start_date), HOUR(start_date)
ORDER BY gun, saat;
Ekranda 09:00–09:59 biçiminde bir etiket üretmek sunum katmanının işi olabilir. Sorgudan sayısal saat almak, sıralamayı ve grafik oluşturmayı daha anlaşılır tutar.
GROUP BY eksikse ilk tarih güvenilir değildir
Eski örnekte gruplama kaldırılınca toplamın ilk tarihin yanında gösterileceği söyleniyordu; buna güvenilemez. ONLY_FULL_GROUP_BY etkin olduğunda uygun olmayan toplama sorgusu reddedilir. Mod kapalıysa seçilen tarihin hangisi olacağı garanti edilmez. Toplam istiyorsanız yalnız COUNT(*) seçin; günlük dağılım istiyorsanız gruplamayı koruyun. MySQL GROUP BY kuralları bunu açıklar.
Boş saatler ve saat dilimi
Hiç kaydı olmayan saat, bu sorguda sıfır değerli bir satır olarak görünmez. Grafikte bütün saatler gerekiyorsa uygulamada 0–23 dizisini oluşturup sorgu sonucuyla doldurun veya takvim/saat tablosuyla LEFT JOIN kullanın. Böyle bir birleştirmede boş eşleşmeyi saymamak için sağ tablonun NULL olmayan anahtarını sayın; körlemesine COUNT(*) kullanmayın.
TIMESTAMP değerleri oturum saat dilimine göre çevrilir; DATETIME aynı otomatik dönüşümü yapmaz. UTC saklanan bir alan için “bugün” sınırlarını hangi saat diliminde hesapladığınızı açıkça belirleyin. Yaz saati geçişi olan bölgelerde bir yerel gün her zaman 24 saat değildir. MySQL saat dilimi belgesi bu ayrımı ele alır.
Tablo büyüdüğünde kontrol
start_date üzerinde uygun bir indeks aralık taramasına yardımcı olabilir; kullanımını EXPLAIN ile kontrol edin. İndeks olsa da seçilen aralık ve gruplama maliyeti önemlidir. Kullanıcıdan gelen başlangıç/bitiş değerlerini PHP tarafında parametreli sorguya bağlayın; tarihleri SQL metnine birleştirmeyin. Kabul testine sınır anlarını, kesirli saniyeleri ve kayıtsız saatleri mutlaka ekleyin.