Data mentah di kolom jarang langsung siap tampil: harga perlu pembulatan, nama pelanggan kadang menyimpan spasi berlebih, dan NULL harus diganti nilai cadangan. Fungsi scalar menyelesaikan semua itu di dalam query itu sendiri — satu nilai masuk, satu nilai keluar, diproses baris demi baris. Ini berbeda dari fungsi agregat yang meringkas banyak baris menjadi satu seperti yang sudah kita bahas pada Chapter Fungsi Agregat. Kita akan mengelompokkan puluhan fungsi bawaan ke dalam lima kategori dan mengujinya satu per satu.

Data Contoh #

Chapter ini memakai satu tabel dari domain toko. Kolom stok sengaja memuat NULL untuk latihan penanganan nilai kosong:

sql
CREATE TABLE produk (
  id INTEGER PRIMARY KEY,
  nama TEXT NOT NULL,
  harga REAL NOT NULL,
  stok INTEGER
);

INSERT INTO produk (id, nama, harga, stok) VALUES
  (1, 'Kopi Gayo', 45000.0, 20),
  (2, 'Teh Melati', 18000.0, 35),
  (3, 'Gula Aren', 25000.0, NULL),
  (4, 'Kopi Toraja', 52000.0, 10),
  (5, 'Sirup Vanila', 27500.5, 0);

Fungsi Matematika #

abs() mengembalikan nilai mutlak dan round() membulatkan angka pecahan ke jumlah digit tertentu. Perhatikan bahwa round() selalu menghasilkan nilai REAL — lihat 3.0 dan 2.0 pada output:

sql
SELECT abs(-2500), round(31714.2857142857, 2), round(2.5), round(2);

Output yang Dihasilkan:

text
2500|31714.29|3.0|2.0

min() dan max() punya dua wajah: dengan satu argumen kolom keduanya bekerja sebagai agregat, tetapi dengan dua argumen atau lebih keduanya menjadi fungsi scalar yang memilih nilai terkecil atau terbesar di antara argumen-argumennya:

sql
SELECT min(3, 1, 2), max(3, 1, 2);

Output yang Dihasilkan:

text
1|3

Bentuk scalar ini berguna untuk membatasi nilai di tiap baris, misalnya menjepit harga agar tidak melewati 30000:

sql
SELECT nama, min(harga, 30000) AS dibatasi FROM produk ORDER BY id;

Output yang Dihasilkan:

text
Kopi Gayo|30000
Teh Melati|18000.0
Gula Aren|25000.0
Kopi Toraja|30000
Sirup Vanila|27500.5

min() mengembalikan argumen yang menang apa adanya — 30000 tetap integer karena yang menang adalah angka kedua, sementara 18000.0 tetap REAL karena yang menang adalah harga dari kolom.

Fungsi Teks #

length() menghitung jumlah karakter, upper() dan lower() mengubah kapitalisasi:

sql
SELECT length('Kopi Gayo'), upper('kopi'), lower('GAYO');

Output yang Dihasilkan:

text
9|KOPI|gayo

substr() memotong teks. Argumen kedua adalah posisi awal (bisa negatif, dihitung dari belakang) dan argumen ketiga adalah jumlah karakter:

sql
SELECT substr('Kopi Gayo', 1, 4), substr('Kopi Gayo', 6), substr('Kopi Gayo', -5);

Output yang Dihasilkan:

text
Kopi|Gayo| Gayo

instr() mencari posisi pertama sebuah substring (mengembalikan 0 bila tidak ditemukan), sedangkan replace() mengganti semua kemunculannya:

sql
SELECT instr('Kopi Gayo', 'Gayo'), replace('Kopi Gayo', 'Gayo', 'Toraja');

Output yang Dihasilkan:

text
6|Kopi Toraja

Keluarga trim() membersihkan spasi: trim() dari kedua sisi, ltrim() dari kiri, rtrim() dari kanan. Tanda kurung siku membuat hasil pemotongan terlihat jelas:

sql
SELECT '[' || trim('  Kopi Gayo  ') || ']', '[' || ltrim('  Kopi  ') || ']', '[' || rtrim('  Kopi  ') || ']';

Output yang Dihasilkan:

text
[Kopi Gayo]|[Kopi  ]|[  Kopi]

Memformat Keluaran dengan printf dan format #

printf() menyusun teks dari placeholder seperti %s untuk teks dan %d untuk bilangan bulat — persis rekan SQL dari fungsi printf() di bahasa C. Mulai SQLite 3.38 tersedia alias bernama format() dengan perilaku identik. Flag koma mengelompokkan ribuan:

sql
SELECT printf('%s: %d unit', 'Kopi Gayo', 20), format('Rp%,d', 45000);

Output yang Dihasilkan:

text
Kopi Gayo: 20 unit|Rp45,000

Fungsi Logika dan Penanganan NULL #

Empat fungsi berikut paling sering menyelamatkan query dari nilai kosong. coalesce() mengembalikan argumen non-NULL pertama, ifnull() versi dua-argumennya, nullif() mengembalikan NULL bila kedua argumen sama, dan iif() (hadir sejak SQLite 3.32) mengevaluasi percabangan:

sql
SELECT coalesce(NULL, NULL, 'Cadangan'), ifnull(NULL, 0), nullif('a', 'a'), nullif('a', 'b');

Output yang Dihasilkan:

text
Cadangan|0||a

iif(kondisi, a, b) mengembalikan a bila kondisi benar dan b bila salah — padanan CASE WHEN yang ringkas:

sql
SELECT nama, iif(stok IS NULL, 'tidak diketahui', 'tercatat') AS status
FROM produk ORDER BY id;

Output yang Dihasilkan:

text
Kopi Gayo|tercatat
Teh Melati|tercatat
Gula Aren|tidak diketahui
Kopi Toraja|tercatat
Sirup Vanila|tercatat

Fungsi Pemeriksa Nilai #

Kelompok terakhir memeriksa tipe dan representasi nilai. typeof() mengembalikan nama tipe, quote() menghasilkan bentuk literal SQL, hex() mengonversi teks ke heksadesimal per byte UTF-8, dan unicode() mengembalikan kode karakter pertama:

sql
SELECT typeof(harga), quote(nama), hex('Ab'), unicode('B') FROM produk WHERE id = 1;

Output yang Dihasilkan:

text
real|'Kopi Gayo'|4162|66

Tabel Ringkas per Kategori #

KategoriFungsiKegunaan
Matematikaabs(), round(), min()/max() multi-argNilai mutlak, pembulatan, pembatasan nilai per baris
Tekslength(), upper(), lower(), substr(), instr(), replace(), trim(), ltrim(), rtrim()Membersihkan dan memotong teks
Formatprintf(), format()Menyusun teks keluaran dengan placeholder
Logikacoalesce(), ifnull(), nullif(), iif()Nilai cadangan dan percabangan
Inspeksitypeof(), quote(), hex(), unicode()Memeriksa tipe dan representasi nilai

Sebagai penutup, kita gabungkan beberapa kategori menjadi satu daftar harga yang rapi:

sql
SELECT format('%-12s', trim(nama)) AS nama,
       format('Rp%,d', round(harga)) AS harga,
       iif(stok IS NULL, 'stok tak diketahui', stok || ' unit') AS info_stok
FROM produk
ORDER BY harga DESC;

Output yang Dihasilkan:

text
Kopi Toraja |Rp52,000|10 unit
Kopi Gayo   |Rp45,000|20 unit
Sirup Vanila|Rp27,501|0 unit
Gula Aren   |Rp25,000|stok tak diketahui
Teh Melati  |Rp18,000|35 unit

Mari kita bedah query di atas baris per baris:

  1. Baris 1 (format('%-12s', trim(nama))): Fungsi trim() membuang spasi di kedua sisi nama, lalu format() meratakannya di ruang 12 karakter agar kolom lurus; tanda minus membuat teks rata kiri.
  2. Baris 2 (format('Rp%,d', round(harga))): round() membulatkan harga ke bilangan bulat REAL, kemudian placeholder %d mengonversinya ke integer dan flag koma menambahkan pemisah ribuan — perhatikan 27500.5 menjadi Rp27,501.
  3. Baris 3 (iif(stok IS NULL, ...)): Cabang pertama mengisi teks untuk stok kosong; cabang kedua merekatkan angka stok dengan kata unit lewat operator ||.
  4. Baris 5 (ORDER BY harga DESC): Urutan menurun membuat produk termahal berada di atas, sehingga output deterministik dan mudah dibaca.

Fungsi scalar memproses nilai pada baris yang sama. Tantangan berikutnya adalah nilai yang berubah seiring waktu — tanggal dan waktu — yang dibahas pada Chapter Bekerja dengan Tanggal dan Waktu.