MariaDB ve MySQL’de ROUND, FLOOR ve CEIL ile Sayı Yuvarlama
Veritabanı sorgularında sayıları yuvarlamak, günlük hayatta karşılaştığımız en temel ihtiyaçlardan biri. Fiyat hesaplamaları, istatistiksel raporlar, stok yönetimi… Bunların hepsinde bir noktada “bu sayıyı nasıl yuvarlayacağım?” sorusuyla karşılaşıyorsunuz. MySQL ve MariaDB’de bu iş için üç temel fonksiyon var: ROUND, FLOOR ve CEIL. Basit görünseler de doğru kullanıldıklarında çok güçlü araçlar haline geliyorlar. Gelin bu fonksiyonları derinlemesine inceleyelim ve gerçek dünya senaryolarıyla pekiştirelim.
ROUND Fonksiyonu: Matematiksel Yuvarlama
ROUND, en çok kullanılan yuvarlama fonksiyonudur. Matematikte öğrendiğimiz klasik yuvarlama mantığıyla çalışır: 0.5 ve üzeri yukarı, 0.5 altı aşağı yuvarlar.
Temel sözdizimi şu şekildedir:
ROUND(sayi, ondalik_basamak_sayisi)
İkinci parametre opsiyoneldir. Eğer yazmazsanız, sonucu tam sayıya yuvarlar.
-- Temel ROUND örnekleri
SELECT ROUND(4.5); -- Sonuç: 5
SELECT ROUND(4.4); -- Sonuç: 4
SELECT ROUND(4.567, 2); -- Sonuç: 4.57
SELECT ROUND(4.561, 2); -- Sonuç: 4.56
SELECT ROUND(4.565, 2); -- Sonuç: 4.57
SELECT ROUND(1234.56, -2); -- Sonuç: 1200 (negatif basamak!)
Son örnekteki negatif basamak sayısı çok işe yarar. Ondalık kısmı değil, tam sayı kısmını yuvarlıyorsunuz. Mesela büyük rakamları binler ya da yüzler bazında raporlamak istediğinizde bu özelliği kullanabilirsiniz.
Gerçek Dünya: E-ticaret Fiyat Hesaplama
Bir e-ticaret sisteminde çalışıyorsunuz. Ürünlere KDV eklendikten sonra fiyatlar çirkin ondalık sayılara dönüşüyor. Bu tabloyu düşünelim:
-- Örnek products tablosu
CREATE TABLE products (
id INT AUTO_INCREMENT PRIMARY KEY,
product_name VARCHAR(100),
price DECIMAL(10, 4),
kdv_rate DECIMAL(5, 2)
);
INSERT INTO products (product_name, price, kdv_rate) VALUES
('Laptop', 15000.0000, 18.00),
('Mouse', 249.9900, 18.00),
('Klavye', 399.5000, 18.00),
('Monitor', 4599.9900, 18.00);
KDV dahil fiyatları hesaplayıp iki ondalık basamakla gösteriyoruz:
-- KDV dahil fiyatları ROUND ile hesapla
SELECT
product_name,
price AS kdv_haric,
ROUND(price * (1 + kdv_rate / 100), 2) AS kdv_dahil,
ROUND(price * (1 + kdv_rate / 100) * 0.90, 2) AS indirimli_fiyat
FROM products;
Bu sorgu size temiz, iki ondalık basamaklı fiyatlar döndürür. Müşteriye gösterilen fiyat hiçbir zaman “4127.991800” gibi bir şey olmaz.
ROUND ile Yüzde Hesaplama
-- Sipariş başarı oranı hesaplama
SELECT
DATE_FORMAT(order_date, '%Y-%m') AS ay,
COUNT(*) AS toplam_siparis,
SUM(CASE WHEN status = 'completed' THEN 1 ELSE 0 END) AS tamamlanan,
ROUND(
SUM(CASE WHEN status = 'completed' THEN 1 ELSE 0 END) * 100.0 / COUNT(*),
1
) AS basari_orani
FROM orders
GROUP BY DATE_FORMAT(order_date, '%Y-%m')
ORDER BY ay DESC;
Bu sorgu size “Ocak 2024: %87.3 başarı oranı” gibi temiz sonuçlar verir. Virgülden sonra beş haneli saçma sayılar yerine düzgün bir yüzde değeri elde edersiniz.
FLOOR Fonksiyonu: Her Zaman Aşağı Yuvarla
FLOOR fonksiyonu, sayıyı her zaman aşağıya doğru, yani kendisinden küçük en yakın tam sayıya yuvarlar. Matematikteki “taban” fonksiyonudur.
SELECT FLOOR(4.9); -- Sonuç: 4 (4.9 olmasına rağmen)
SELECT FLOOR(4.1); -- Sonuç: 4
SELECT FLOOR(-4.1); -- Sonuç: -5 (negatif sayılarda dikkat!)
SELECT FLOOR(-4.9); -- Sonuç: -5
SELECT FLOOR(5.0); -- Sonuç: 5
Negatif sayılarda FLOOR’un davranışına dikkat edin. -4.1’i “aşağı” yuvarladığınızda -5 olur, -4 değil. Çünkü sayı doğrusunda -5, -4.1’den daha aşağıdadır.
Gerçek Dünya: Yaş Hesaplama ve Kategorizasyon
Kullanıcıların yaşını tam yıl olarak hesaplamak için FLOOR mükemmel bir araçtır:
-- Kullanıcı yaşını tam yıl olarak hesapla
SELECT
user_name,
birth_date,
FLOOR(DATEDIFF(CURDATE(), birth_date) / 365.25) AS yas,
CASE
WHEN FLOOR(DATEDIFF(CURDATE(), birth_date) / 365.25) < 18 THEN 'Genç'
WHEN FLOOR(DATEDIFF(CURDATE(), birth_date) / 365.25) BETWEEN 18 AND 35 THEN 'Yetişkin'
WHEN FLOOR(DATEDIFF(CURDATE(), birth_date) / 365.25) BETWEEN 36 AND 60 THEN 'Orta Yaş'
ELSE 'Kıdemli'
END AS yas_grubu
FROM users;
DATEDIFF ile gün farkını alıp 365.25’e bölüyoruz (artık yılları hesaba katmak için). FLOOR sayesinde “28.7 yaşında” değil, “28 yaşında” sonucunu elde ediyoruz.
Gerçek Dünya: Stok Yönetiminde Tam Paket Hesabı
Bir depo yönetim sisteminde çalışıyorsunuz. Ürünler kutularda satılıyor ve müşteri ne kadar sipariş ederse etsin, sadece tam kutu gönderebiliyorsunuz:
-- Kaç tam kutu gönderilebilir hesaplama
SELECT
product_name,
stock_quantity,
box_size,
FLOOR(stock_quantity / box_size) AS gonderilebilir_kutu_sayisi,
stock_quantity - (FLOOR(stock_quantity / box_size) * box_size) AS artik_stok
FROM warehouse_products
WHERE stock_quantity > 0;
Bu sorguda FLOOR sayesinde “3.7 kutu” gibi bir saçmalık yerine “3 kutu” sonucu alıyorsunuz. Artık stok miktarını da hesaplamak için bu değeri kullanıyorsunuz.
Gerçek Dünya: Sayfalama (Pagination) Hesabı
Kaç sayfa olduğunu hesaplamak için genellikle CEIL kullanılır (birazdan göreceğiz) ama bazen FLOOR da işe girer:
-- Tam dolu sayfaları hesapla (FLOOR ile)
SELECT
COUNT(*) AS toplam_kayit,
FLOOR(COUNT(*) / 25) AS tam_dolu_sayfa,
MOD(COUNT(*), 25) AS son_sayfadaki_kayit
FROM blog_posts
WHERE status = 'published';
CEIL Fonksiyonu: Her Zaman Yukarı Yuvarla
CEIL (ya da CEILING, ikisi de aynı işi yapar), FLOOR’un tam tersidir. Sayıyı her zaman yukarıya, kendisinden büyük en yakın tam sayıya yuvarlar.
SELECT CEIL(4.1); -- Sonuç: 5 (sadece 4.1 olmasına rağmen!)
SELECT CEIL(4.9); -- Sonuç: 5
SELECT CEIL(-4.1); -- Sonuç: -4 (negatif sayılarda FLOOR'un tersi)
SELECT CEIL(-4.9); -- Sonuç: -4
SELECT CEIL(5.0); -- Sonuç: 5 (tam sayı ise değişmez)
SELECT CEILING(4.3); -- Sonuç: 5 (CEILING da aynı şeyi yapar)
Gerçek Dünya: Sayfalama Hesabı (Pagination)
Sayfalama için CEIL’in kullanımı neredeyse standart haline gelmiştir:
-- Blog yazıları için toplam sayfa sayısı
SELECT
COUNT(*) AS toplam_yazi,
CEIL(COUNT(*) / 10) AS toplam_sayfa_sayisi
FROM blog_posts
WHERE status = 'published';
-- Kategorilere göre sayfa sayısı
SELECT
category_name,
COUNT(p.id) AS yazi_sayisi,
CEIL(COUNT(p.id) / 10.0) AS sayfa_sayisi
FROM categories c
LEFT JOIN blog_posts p ON c.id = p.category_id AND p.status = 'published'
GROUP BY c.id, c.category_name
ORDER BY yazi_sayisi DESC;
Neden CEIL? Çünkü 25 yazınız varsa ve sayfada 10 yazı gösteriyorsanız, 2 tam sayfa + 5 yazılık bir sayfa = 3 sayfa gerekir. FLOOR kullansaydınız 2 dönüp son 5 yazıyı kaybederdiniz.
Gerçek Dünya: Teslimat Süre Tahmini
Bir lojistik sisteminde mesafeye göre gün hesaplaması:
-- Teslimat süresi hesaplama (her başlayan gün bir gün sayılır)
SELECT
order_id,
customer_name,
destination_city,
distance_km,
CEIL(distance_km / 500.0) AS tahmini_gun,
DATE_ADD(order_date, INTERVAL CEIL(distance_km / 500.0) DAY) AS tahmini_teslim_tarihi
FROM orders
WHERE status = 'processing';
Burada CEIL kritik. 600 km’lik bir mesafe 1.2 güne denk gelir ama siz müşteriye “1.2 günde gelir” diyemezsiniz. CEIL ile bu 2 güne yuvarlanır ve müşteri beklentisi doğru yönetilir.
Üç Fonksiyonu Birlikte Kullanmak
Gerçek projelerde bu üç fonksiyonu yan yana kullanmak sık karşılaşılan bir durumdur:
-- Üç fonksiyonun karşılaştırmalı kullanımı
SELECT
product_name,
raw_price,
FLOOR(raw_price) AS floor_fiyat,
ROUND(raw_price, 0) AS round_fiyat,
CEIL(raw_price) AS ceil_fiyat,
-- Fiyat aralığı için alt ve üst sınır
FLOOR(raw_price / 100) * 100 AS alt_sinir,
CEIL(raw_price / 100) * 100 AS ust_sinir
FROM (
SELECT
product_name,
price * 1.18 AS raw_price
FROM products
) AS hesapli_fiyatlar;
Bu sorgu size her ürün için hem yuvarlama farklarını gösterir, hem de ürünün hangi fiyat aralığında olduğunu hesaplar. Raporlamada çok işe yarar.
İleri Düzey: ROUND ile Ondalık Hassasiyeti Kontrol Etme
Finansal sistemlerde ondalık hassasiyeti çok önemlidir. Bankacılık sistemlerinde hatalı yuvarlama ciddi sorunlara yol açabilir:
-- Banka hesap bakiyesi hesaplama
-- Faiz hesaplaması sonucu oluşan küsüratları temizleme
SELECT
account_id,
customer_name,
balance,
annual_rate,
-- Günlük faiz hesaplama
ROUND(balance * annual_rate / 100 / 365, 4) AS gunluk_faiz,
-- Aylık faiz (iki ondalık basamak, kuruş hassasiyeti)
ROUND(balance * annual_rate / 100 / 12, 2) AS aylik_faiz,
-- Yeni bakiye
ROUND(balance + (balance * annual_rate / 100 / 12), 2) AS yeni_bakiye
FROM bank_accounts
WHERE status = 'active';
Dikkat edin, her adımda ROUND kullanıyoruz. Eğer ara hesaplamalarda ROUND kullanmazsanız, kayan noktalı sayıların yarattığı milimetrik hatalar birikip sonunda ciddi tutarsızlıklara dönüşebilir.
Pratik Senaryo: Performans Raporu
Bir web uygulamasının performans metriklerini raporladığınızı düşünelim:
-- Sunucu performans raporu
SELECT
server_name,
DATE(metric_time) AS tarih,
ROUND(AVG(cpu_usage), 1) AS ort_cpu,
ROUND(MAX(cpu_usage), 1) AS maks_cpu,
ROUND(AVG(memory_usage_gb), 2) AS ort_ram_gb,
ROUND(AVG(response_time_ms), 0) AS ort_yanit_ms,
-- Uptime yüzdesi (iki ondalık)
ROUND(
SUM(CASE WHEN status = 'healthy' THEN 1 ELSE 0 END) * 100.0 / COUNT(*),
2
) AS uptime_yuzde,
-- Kapasite kullanım kategorisi
CASE
WHEN ROUND(AVG(cpu_usage), 1) < 50 THEN 'Normal'
WHEN ROUND(AVG(cpu_usage), 1) BETWEEN 50 AND 80 THEN 'Yuksek'
ELSE 'Kritik'
END AS kapasite_durumu
FROM server_metrics
WHERE metric_time >= DATE_SUB(NOW(), INTERVAL 7 DAY)
GROUP BY server_name, DATE(metric_time)
ORDER BY tarih DESC, server_name;
Bu sorgu haftalık sunucu raporunuzu temiz ve okunabilir hale getirir. “87.3571428…” yerine “87.4” görürsünüz.
Sık Yapılan Hatalar
ROUND’un İkinci Parametresini Unutmak
-- YANLIŞ: Tüm ondalık kısım gider
SELECT ROUND(99.99); -- Sonuç: 100, kuruşlar kayboldu!
-- DOĞRU: İki ondalık basamak koru
SELECT ROUND(99.99, 2); -- Sonuç: 99.99
FLOOR ve CEIL’i Negatif Sayılarda Karıştırmak
-- Negatif sayılarda davranışı test edin
SELECT
-4.3 AS sayi,
FLOOR(-4.3) AS floor_sonuc, -- -5
CEIL(-4.3) AS ceil_sonuc, -- -4
ROUND(-4.3) AS round_sonuc; -- -4
Bölme İşleminde Tam Sayı Bölmesi Tuzağı
-- YANLIŞ: MySQL tam sayı bölmesi yapar, CEIL işe yaramaz!
SELECT CEIL(7 / 2); -- Sonuç: 4 (3.5 değil, 3 sonra CEIL = 4 değil!)
-- DOĞRU: Float bölmesi için nokta ekleyin
SELECT CEIL(7 / 2.0); -- Sonuç: 4 (3.5'in CEIL'i = 4, doğru!)
SELECT CEIL(7.0 / 2); -- Bu da çalışır
Bu ince hata çok sık yapılır. Özellikle sayfa sayısı hesaplarken tam sayı bölmesi yapıyorsanız sonuçlarınız yanlış çıkar.
Fonksiyonların Performans Etkisi
Bu fonksiyonlar matematiksel işlemler yaptığı için hesaplama maliyeti düşüktür, ancak büyük veri setlerinde dikkatli olmak gerekir:
-- Büyük tablolarda indeks kullanımına dikkat
-- Bu sorgu indeks kullanamaz (fonksiyon wrapped column)
EXPLAIN SELECT * FROM orders
WHERE ROUND(total_price, 0) = 100;
-- Bu sorgu indeks kullanır
EXPLAIN SELECT * FROM orders
WHERE total_price BETWEEN 99.50 AND 100.49;
WHERE koşulunda bir sütuna fonksiyon uyguladığınızda MySQL o sütundaki indeksi genellikle kullanamaz. Yuvarlama mantığını WHERE koşuluna değil, SELECT listesine veya HAVING kısmına taşımaya çalışın.
Sonuç
ROUND, FLOOR ve CEIL fonksiyonları küçük görünse de doğru kullanıldığında sorgularınızın kalitesini ciddi ölçüde artırır. Özetlemek gerekirse:
- ROUND: Klasik matematiksel yuvarlama gerektiğinde, özellikle para ve yüzde hesaplamalarında kullanın.
- FLOOR: “En fazla kaç tane sığar?” veya “Tam yıl kaç?” gibi sorularda, her zaman aşağı yuvarlamak istediğinizde kullanın.
- CEIL: Sayfalama, teslimat günü gibi “bir tane bile fazla varsa bir üst değeri al” mantığında kullanın.
Negatif sayılardaki davranışlara dikkat edin, bölme işlemlerinde float kullanın ve WHERE koşullarında fonksiyon sarmalamaktan kaçının. Bu üç kuralı aklınızda tutarsanız bu fonksiyonlarla ilgili büyük çoğunlukla sorun yaşamazsınız. Finansal sistemlerde çalışıyorsanız özellikle ara hesaplamalarda ROUND kullanma alışkanlığı edinin, ileride başınızı ağrıtacak kayan nokta hatalarından sizi korur.
