TL;DR
UPPER mengubah semua huruf jadi kapital dan LOWER mengubah semua jadi huruf kecil di SQL. Sintaksnya UPPER(kolom) dan LOWER(kolom). Fungsi ini penting karena PostgreSQL membandingkan string secara case-sensitive, jadi WHERE email = 'Budi@Mail.com' nggak bakal ketemu baris yang tersimpan sebagai 'budi@mail.com'.
UPPER bikin semua huruf jadi kapital. LOWER bikin semua jadi huruf kecil. Sintaksnya UPPER(kolom) dan LOWER(kolom).
Di Excel, huruf besar-kecil cuma masalah kosmetik. Di PostgreSQL, dia bikin baris hilang dari hasil query.
SELECT * FROM pelanggan WHERE email = 'budi@mail.com';
-- 0 baris
-- padahal di tabel ada 'BUDI@Mail.com'
Nggak ada error. Cuma hasil kosong, dan kamu bingung sejam.
Tergantung database dan collation-nya. Ini yang bikin banyak orang kejebak.
| Database | Perbandingan teks default | Efeknya |
|---|---|---|
| PostgreSQL | Case-sensitive | 'Jakarta' ≠ 'jakarta' |
| MySQL (collation _ci) | Case-insensitive | 'Jakarta' = 'jakarta' |
| SQL Server | Tergantung collation | Default biasanya case-insensitive |
| SQLite | Case-sensitive | 'Jakarta' ≠ 'jakarta' |
Artinya query yang jalan mulus di MySQL bisa langsung kosong hasilnya waktu dipindah ke PostgreSQL. Aku pernah kena ini waktu migrasi, dan butuh dua jam buat sadar.
Cara aman yang jalan di semua database: seragamkan dulu pakai LOWER.
SELECT * FROM pelanggan
WHERE LOWER(email) = LOWER('budi@mail.com');
Dua sisi, bukan cuma sebelah. Kalau cuma kolomnya yang di-LOWER tapi nilai pembandingnya masih kapital, tetap nggak ketemu.
GROUP BY ngelompokkan baris berdasarkan nilai persis. Di PostgreSQL, tiga cara nulis Jakarta = tiga grup.
SELECT kota, COUNT(*) FROM pelanggan GROUP BY kota;
-- kota | count
-- jakarta | 1
-- JAKARTA | 1
-- Jakarta | 1
Laporan penjualan per kota kamu langsung ngaco. Total globalnya bener, tapi ranking kotanya kacau, dan itu yang dilihat manajemen.
Perbaikannya: seragamkan sebelum digrupkan.
SELECT INITCAP(LOWER(kota)) AS kota,
COUNT(*) AS jumlah
FROM pelanggan
GROUP BY 1
ORDER BY jumlah DESC;
INITCAP bikin huruf pertama tiap kata kapital, setara PROPER di Excel. Ada di PostgreSQL dan Oracle, nggak ada di MySQL dan SQL Server.
Tabel pelanggan di dataset toko_berkah punya 1.240 baris dengan kolom email. Data ini gabungan dari form website, input kasir, dan import dari marketplace.
Waktu tim marketing hitung email unik pakai COUNT(DISTINCT email), hasilnya 1.187.
Setelah di-LOWER, angkanya turun jadi 1.094.
SELECT COUNT(DISTINCT email) AS email_mentah, -- 1187
COUNT(DISTINCT LOWER(email)) AS email_bersih -- 1094
FROM pelanggan;
93 email itu orang yang sama, cuma beda kapitalisasi. Artinya 8% dari daftar kirim newsletter bakal dapat email dua kali. Itu jalan cepat menuju tombol unsubscribe.
Email itu standarnya nggak peka huruf besar-kecil di sisi mail server. Tapi database kamu nggak tau itu.
Ini konsekuensi yang jarang dibahas. Begitu kolom dibungkus fungsi, index di kolom itu jadi nggak kepakai.
-- Index di kolom email? Percuma. Database scan semua baris.
SELECT * FROM pelanggan WHERE LOWER(email) = 'budi@mail.com';
Di tabel 5 juta baris, ini beda antara query 20 milidetik dan query 14 detik.
Ada dua jalan keluar.
CREATE INDEX idx_pelanggan_email_lower
ON pelanggan (LOWER(email));
Sekarang PostgreSQL punya index yang bentuknya udah lowercase. Query yang pakai LOWER(email) bisa cepat lagi. Detailnya ada di dokumentasi expression index PostgreSQL.
BEGIN;
UPDATE pelanggan
SET email = LOWER(email)
WHERE email <> LOWER(email);
COMMIT;
Ini yang paling bersih buat jangka panjang. Habis itu pastikan aplikasi selalu nyimpen email dalam huruf kecil, biar masalahnya nggak balik lagi bulan depan.
Konsep transaksi di sini penting. Kalau hasilnya nggak sesuai, kamu masih bisa ROLLBACK. Lebih lengkap di glosarium transaksi.
PostgreSQL punya operator ILIKE yang cuek huruf besar-kecil.
SELECT * FROM pelanggan WHERE email ILIKE 'budi@mail.com';
SELECT * FROM pelanggan WHERE nama ILIKE '%santoso%';
Lebih ringkas dari LOWER di dua sisi, dan dukung wildcard %. Tapi ILIKE cuma ada di PostgreSQL, jadi query kamu nggak portabel.
Ada juga tipe data CITEXT yang perbandingannya otomatis cuek huruf. Pas buat kolom email dan username, tapi butuh extension dan bikin skema kamu jadi kurang standar.
Aturan praktis: buat data yang emang harusnya cuek huruf (email, username, kode), simpan lowercase di database. Buat pencarian ad-hoc, ILIKE nggak apa-apa.
WHERE LOWER(email) = 'Budi@Mail.com' tetap gagal. Dua-duanya harus di-LOWER.' jakarta' tetap beda dari 'jakarta'. Butuh TRIM SQL juga.Kombinasi yang aku pakai buat bersihin kolom teks apa pun:
SELECT INITCAP(LOWER(TRIM(nama))) AS nama_bersih
FROM pelanggan;
TRIM beresin spasi, LOWER seragamkan huruf, INITCAP bikin rapi buat dibaca.
Tergantung databasenya. PostgreSQL dan SQLite case-sensitive. MySQL dengan collation default cuek huruf. SQL Server tergantung collation. Kalau nggak yakin, seragamkan pakai LOWER. Itu aman di mana-mana.
LOWER ngubah nilainya dulu, baru dibandingkan. ILIKE operator perbandingan yang cuek huruf dan dukung wildcard. Buat pencocokan persis, LOWER lebih jelas. Buat pencarian sebagian teks, ILIKE lebih ringkas.
Kolom yang dibungkus fungsi bikin index nggak kepakai, jadi database scan seluruh tabel. Solusinya bikin functional index di LOWER(email).
INITCAP bikin huruf pertama tiap kata kapital, setara PROPER di Excel. Ada di PostgreSQL dan Oracle, nggak ada di MySQL dan SQL Server.
Simpan datanya udah lowercase, khususnya email dan username. Index tetap kepakai dan query nggak perlu dibungkus fungsi.
Yang perlu nempel:
Kalau perbandingan kamu masih gagal setelah huruf diseragamkan, tersangka berikutnya spasi. Cek TRIM SQL.
Mau latihan bersihin data langsung di browser tanpa install database? Coba modul fungsi string di NgulikSQL.
Mau praktek langsung? Mulai latihan SQL gratis
Latihan interaktif, langsung di browser.
Analisa per kuartal, hari kerja, atau musim jadi ribet kalau tiap query ngitung ulang atribut tanggal. Tabel kalender nyimpen semua atribut itu sekali, biar tinggal di-JOIN.
Laporan penjualan harian sering bolong di hari tanpa transaksi. Ini cara bikin deret tanggal lengkap di SQL biar tiap hari muncul, walau nilainya nol.
Struktur organisasi tersimpan sebagai kolom id_atasan yang saling nunjuk. Ini cara narik rantai jabatan, hitung total bawahan, dan span of control cuma pakai SQL.