SQLite'ta Beklediğinizden Çok Daha Fazla Matematik Var
SQLite minimal yapısıyla bilinir ama aslında oldukça kapsamlı bir sayısal fonksiyon seti ile geliyor: yuvarlama, mutlak değer, tavan ve taban, üs, kök, logaritma, trigonometri ve rastgele sayılar. Matematik fonksiyonlarının büyük çoğunluğu SQLite 3.35 (2021) ile eklendi; yani Python ile gelen sürüm, Node, tarayıcıların eski WebSQL muadili ya da resmi CLI gibi makul ölçüde güncel her kurulumda bu fonksiyonlar hazır şekilde elinizin altında.
Ayrıntıya girmeden önce kısa bir tadımlık:
Altı fonksiyon, tek satır sonuç. Sayfanın geri kalanında her fonksiyon ailesinin ne işe yaradığını ve dikkat etmeniz gereken püf noktaları tek tek anlatacağım.
ROUND: En Sık Kullanacağın Fonksiyon
ROUND(value, digits) değeri belirttiğiniz ondalık basamak sayısına yuvarlar. İkinci parametre isteğe bağlı — boş bırakırsanız en yakın tam sayıya yuvarlar, ama sonuç yine ondalıklı (floating-point) bir değer olarak döner:
Dikkat etmeniz gereken birkaç nokta var:
ROUND(3.14159)sana3değil,3.0döner. Tam sayı istiyorsanız yaCAST(ROUND(x) AS INTEGER)kullan ya da doğrudan kırpma içinCAST(x AS INTEGER)yaz.- SQLite, "sıfırdan uzağa yuvarlama" (round half away from zero) mantığını kullanır — yani
2.5,3'e yuvarlanır;-2.5ise-3'e iner. Bazı veritabanları bankacı yuvarlaması (en yakın çifte yuvarlama) yapar; SQLite yapmaz. digitsargümanı negatif de olabilir:ROUND(1234.5, -2)en yakın 100'e yuvarlar ve sonuç1200olur.
Pratikte en sık yazacağın şey, para gösterimleri için ROUND(price, 2) olacak.
ROUND ile CAST aynı şey değil
Çoğu kişi yuvarlama yapacağım derken CAST(x AS INTEGER) kullanır ve sonra canı yanar:
CAST sıfıra doğru kırpar — yani ondalık kısmı kafasına göre atar. ROUND ise en yakın tam sayıya yuvarlar. 2.9 için aralarında tam bir birim fark çıkıyor. Hangisinin davranışı sana uyuyorsa onu seç.
ABS, SIGN ve Bir Sayının İşareti
ABS(x) mutlak değeri döndürür. SIGN(x) ise sayının işaretine göre -1, 0 ya da 1 verir:
ABS, en çok iş gören fonksiyondur — "iki değer arasındaki fark ne kadar" tarzı sorgular için biçilmiş kaftan. SIGN ise daha az kullanılır ama satırları yönlerine göre gruplamak istediğinde (borç/alacak, kâr/zarar gibi) CASE yazma derdinden kurtarır.
CEIL, FLOOR ve TRUNC ile yuvarlama alternatifleri
Bu fonksiyonlar, en yakın değere yuvarlamadan tam sayıya yakın bir sonuç almanı sağlar. CEIL her zaman yukarı yuvarlar, FLOOR her zaman aşağı çeker, TRUNC ise sıfıra doğru kırpar:
Negatif değerlere dikkat et. FLOOR(-2.9) sonucu -3 döner (sıfırdan uzaklaşır), oysa TRUNC(-2.9) sonucu -2 olur (sıfıra yaklaşır). Negatif sayılarla çalışırken FLOOR ve TRUNC farklı sonuçlar üretir; yanlış olanı seçmek klasik bir off-by-one hatasına yol açar.
CEILING, CEIL fonksiyonunun takma adıdır. Hangisi daha okunaklı geliyorsa onu kullanabilirsiniz.
Asıl Tuzak: SQLite Tam Sayı Bölme
Aslında bu bir fonksiyon değil — sadece / operatörü — ama yeni başlayanları gerçek matematik fonksiyonlarından çok daha fazla yanıltıyor:
İki taraf da tam sayıysa SQLite tam sayı bölmesi yapar ve sonucu kırpar. Taraflardan biri REAL olur olmaz tüm ifade ondalıklı sayıya dönüşür. Çözüm basit: en az bir operandın float olmasını garanti edin — ya 2 yerine 2.0 yazın ya da CAST kullanın.
Bu durum özellikle kolon referanslarında baş ağrıtır: total_cents / 100 size bir tam sayı döner. Asıl istediğiniz dolar tutarını almak için total_cents / 100.0 yazmanız gerekir.
MOD fonksiyonu ve % operatörü
MOD(x, y) ifadesi x / y işleminin kalanını verir. % operatörü de aynı işi yapar:
MOD(17, 5) ile 17 % 5 aynı sonucu verir: 2. Sıfıra göre modülde SQLite hata fırlatmaz, NULL döner — çoğu dile göre alışılmadık bir davranış. Bu seni etkiliyorsa böleni önceden kontrol et ya da çağrıyı CASE WHEN y = 0 THEN ... END içine sar.
Fonksiyon ve operatör hâli birbirinin yerine kullanılabilir. Çoğu kişi daha kısa olduğu için % tercih ediyor.
POWER, SQRT, EXP, LOG
Üs ve kök hesapları için:
Birkaç ufak detay var, insanların ayağını kaydırabiliyor:
POW,POWERfonksiyonunun takma adıdır.- SQLite'ta
LOG(x)10 tabanındadır.LN(x)ise doğal logaritmadır. İki argümanlıLOG(b, x)isebtabanında logaritma verir. (Birçok dildelogdoğal logaritmayı ifade ettiği için bu kafa karıştırıcı olabiliyor — ama SQL geleneği galip geldi.) - Negatif bir sayının
SQRTdeğeri hata vermez,NULLdöner. POWER(0, 0)ise gelenek gereği1döndürür.
Bu fonksiyonlar bileşik faiz hesaplama, desibele normalize etme, mesafe bulma gibi geometrik veya üstel matematiğin geçtiği her yerde işinize yarar.
RANDOM ve RANDOMBLOB
RANDOM(), işaretli 64-bit bir tam sayı döndürür ve değer bu aralığın herhangi bir yerinde olabilir:
Belirli bir aralıkta sayı elde etmek için ABS ile sarın (çünkü RANDOM() işaretli değer döndürür) ve % operatörünü kullanın. 0 ile 1 arasında ondalıklı bir sayı için ise sonucu 64-bit en büyük tam sayıya bölmeniz yeterli. SQLite'ta 0–1 arası değer döndüren hazır bir RAND() fonksiyonu yok — bunu kendiniz kurmanız gerekiyor.
RANDOMBLOB(n), n baytlık rastgele veri üretir; oturum token'ları veya test verileri oluşturmak için oldukça kullanışlıdır. Yazdırılabilir bir string elde etmek istiyorsanız HEX() ile birleştirin:
Her çağrı yeni bir değer üretir. Aynı satır içinde, hatta tek bir ifadenin içinde bile RANDOM() fonksiyonunun aynı sayıyı iki kez döndürmesini beklemeyin — her çağrı birbirinden bağımsız çalışır.
Hepsini Bir Araya Getirelim
Küçük bir uygulama örneği: bir ürün tablosunda mesafeleri hesaplayıp fiyatları yuvarlayalım.
price_cents / 100.0 ifadesindeki o .0 aslında işin kilit noktası — bölmeyi reel sayıya çeviriyor, sonra ROUND da değeri iki ondalık basamağa yuvarlıyor. Bu olmasaydı 1299 / 100 size 12.99 değil, 12 verirdi.
Sırada: Tarih ve Saat
Sayısal fonksiyonlar matematik tarafını hallediyor. Ama tarih ve saatlerin kendi araç setine ihtiyacı var — SQLite bunları metin, reel sayı ya da tam sayı olarak saklıyor ve bunları ayrıştırmak, biçimlendirmek ve üzerlerinde hesap yapmak için ufak ama bir o kadar da işlevsel bir fonksiyon kümesi sunuyor. Bir sonraki bölümde tam da bunu ele alacağız.
Sıkça Sorulan Sorular
SQLite'ta 2 ondalık basamağa nasıl yuvarlarım?
ROUND(value, 2) kullanın. İkinci parametre tutulacak ondalık basamak sayısıdır — ROUND(3.14159, 2) size 3.14 döndürür. Tek parametreyle çağırdığınızda ROUND(x) en yakın tam sayıya yuvarlar ama dönüş değeri yine de REAL (kayan nokta) olur; bu da çoğu kişiyi şaşırtıyor.
SQLite'ta CEIL ve FLOOR var mı?
Evet. SQLite 3.35'ten (2021) itibaren matematik fonksiyonları çekirdeğe dahil: CEIL(x), FLOOR(x), SQRT(x), POWER(x, y), LOG(x), EXP(x) ve diğerleri. Daha eski sürümlerde math eklentisi yüklenmediği sürece bunlar gelmez ama Python, Node ve tarayıcılarla gelen modern derlemelerin neredeyse tamamında bu fonksiyonlar zaten etkin.
Neden SQLite'ta 5 / 2 sonucu 2 dönüyor?
Çünkü iki operand da tam sayı olunca SQLite tam sayı bölme yapıp sonucu kırpıyor. 2.5 almak için bir tarafı REAL'e çevirin: 5 / 2.0 veya CAST(5 AS REAL) / 2. Bu aslında bir sayısal fonksiyon meselesi değil; / operatörünün tam sayı argümanlarla varsayılan davranışı.