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.

Bir yanıt yazın

E-posta adresiniz yayınlanmayacak. Gerekli alanlar * ile işaretlenmişlerdir