Data teks jarang tersimpan dalam bentuk yang persis kita butuhkan saat ditampilkan. Nama produk bisa mengandung spasi berlebih dari input yang ceroboh, kode barang perlu diberi awalan nol, dan laporan sering butuh label gabungan antara nama produk dan kategorinya. MySQL menyediakan sekumpulan fungsi string yang bekerja langsung di dalam query, sehingga kita tidak perlu menarik data mentah lalu memformatnya ulang di kode aplikasi. Pada chapter ini kita berlatih fungsi string yang paling sering dipakai sehari-hari memakai satu tabel produk kecil: mengubah huruf besar-kecil, menggabungkan teks, mengukur panjang, memotong, mencari, mengganti, dan merapikan.
Menyiapkan Tabel Latihan #
Kita mulai dengan database latihan belajar_fungsi dan tabel produk berisi delapan baris. Perhatikan satu baris sengaja dibuat “kotor” — nama dengan spasi berlebih di awal dan akhir, seolah hasil input manual yang tidak hati-hati:
DROP DATABASE IF EXISTS belajar_fungsi;
CREATE DATABASE belajar_fungsi;
USE belajar_fungsi;Output yang Dihasilkan:
Query OK, 0 rows affected, 1 warning (0.00 sec)
Query OK, 1 row affected (0.00 sec)
Database changedRespons pertama menyertai 1 warning karena database belajar_fungsi memang belum pernah ada — DROP DATABASE IF EXISTS hanya mengeluarkan peringatan ketika targetnya tidak ditemukan, bukan error. Kata kunci IF EXISTS membuat skrip latihan aman dijalankan berulang kali. Selanjutnya kita buat tabelnya dan mengisinya:
CREATE TABLE produk (
id INT AUTO_INCREMENT PRIMARY KEY,
nama VARCHAR(60) NOT NULL,
kategori VARCHAR(40) NOT NULL,
warna VARCHAR(30) NULL,
harga DECIMAL(10,2) NOT NULL
);
INSERT INTO produk (nama, kategori, warna, harga) VALUES
('Buku Tulis 38', 'Alat Tulis', NULL, 4500.00),
('Pensil 2B', 'Alat Tulis', 'Hitam', 3000.00),
('Penggaris 30 cm', 'Alat Tulis', 'Transparan', 2500.00),
('Spidol Whiteboard', 'Alat Tulis', 'Biru', 6000.00),
('Buku Gambar A4', 'Kertas', NULL, 9000.00),
('Kertas HVS A4', 'Kertas', NULL, 25000.00),
(' Stipo Perekat ', 'Perekat', 'Putih', 6000.00),
('Penghapus', 'Alat Tulis', 'Putih', 2500.00);Output yang Dihasilkan:
Query OK, 0 rows affected (0.00 sec)
Query OK, 8 rows affected (0.00 sec)
Records: 8 Duplicates: 0 Warnings: 0Kolom warna sengaja dibuat boleh NULL karena tidak semua produk punya varian warna yang tercatat. Baris Stipo Perekat akan menjadi bahan latihan fungsi TRIM pada bagian akhir chapter. Setiap contoh pada chapter ini membaca tabel tersebut tanpa pernah mengubah isinya, jadi kita bisa menjalankan blok-blok berikutnya berulang kali dengan hasil yang sama.
Mengubah Huruf Besar dan Kecil #
Fungsi UPPER() mengembalikan salinan teks dengan seluruh huruf menjadi kapital, sedangkan LOWER() kebalikannya:
SELECT nama, UPPER(nama) AS nama_kapital, LOWER(kategori) AS kategori_kecil
FROM produk
ORDER BY id;Output yang Dihasilkan:
+-------------------+-------------------+----------------+
| nama | nama_kapital | kategori_kecil |
+-------------------+-------------------+----------------+
| Buku Tulis 38 | BUKU TULIS 38 | alat tulis |
| Pensil 2B | PENSIL 2B | alat tulis |
| Penggaris 30 cm | PENGGARIS 30 CM | alat tulis |
| Spidol Whiteboard | SPIDOL WHITEBOARD | alat tulis |
| Buku Gambar A4 | BUKU GAMBAR A4 | kertas |
| Kertas HVS A4 | KERTAS HVS A4 | kertas |
| Stipo Perekat | STIPO PEREKAT | perekat |
| Penghapus | PENGHAPUS | alat tulis |
+-------------------+-------------------+----------------+
8 rows in set (0.00 sec)Fungsi ini berguna saat kita ingin tampilan yang seragam tanpa mengubah data aslinya — misalnya header laporan berkapital penuh. Nilai pada kolom nama dan kategori di tabel tetap seperti semula; hasil UPPER dan LOWER hanya hidup di dalam hasil query. Kita juga akan memakai LOWER sebagai alat pencarian yang tidak peduli huruf besar-kecil pada section Filtering dan Sorting.
Menggabungkan Teks dengan CONCAT dan CONCAT_WS #
Fungsi CONCAT() menerima dua argumen atau lebih dan mengembalikannya sebagai satu teks utuh. Fungsi CONCAT_WS() (singkatan with separator) memakai argumen pertama sebagai pemisah di antara argumen-argumen sisanya:
SELECT nama,
CONCAT(nama, ' (', kategori, ')') AS label,
CONCAT_WS(' - ', nama, warna) AS label_warna
FROM produk
ORDER BY id;Output yang Dihasilkan:
+-------------------+--------------------------------+------------------------------+
| nama | label | label_warna |
+-------------------+--------------------------------+------------------------------+
| Buku Tulis 38 | Buku Tulis 38 (Alat Tulis) | Buku Tulis 38 |
| Pensil 2B | Pensil 2B (Alat Tulis) | Pensil 2B - Hitam |
| Penggaris 30 cm | Penggaris 30 cm (Alat Tulis) | Penggaris 30 cm - Transparan |
| Spidol Whiteboard | Spidol Whiteboard (Alat Tulis) | Spidol Whiteboard - Biru |
| Buku Gambar A4 | Buku Gambar A4 (Kertas) | Buku Gambar A4 |
| Kertas HVS A4 | Kertas HVS A4 (Kertas) | Kertas HVS A4 |
| Stipo Perekat | Stipo Perekat (Perekat) | Stipo Perekat - Putih |
| Penghapus | Penghapus (Alat Tulis) | Penghapus - Putih |
+-------------------+--------------------------------+------------------------------+
8 rows in set (0.00 sec)Bedah tiga bagian pada contoh di atas:
CONCAT(nama, ' (', kategori, ')')menempelkan empat potongan teks berurutan tanpa pemisah apa pun — spasi dan tanda kurung harus kita tulis sendiri sebagai argumen.CONCAT_WS(' - ', nama, warna)menyisipkan string' - 'di antara setiap pasangan argumen, sehingga lebih ringkas ketika pemisahnya seragam.- Kolom
warnayang bernilaiNULLmembuat hasilCONCATuntuk baris itu menjadiNULLsepenuhnya, sementaraCONCAT_WShanya melewatiNULLlalu tetap menggabungkan argumen sisanya.
Mengukur Panjang: LENGTH vs CHAR_LENGTH #
MySQL punya dua fungsi panjang yang jawabannya bisa berbeda. LENGTH() menghitung jumlah byte, sedangkan CHAR_LENGTH() menghitung jumlah karakter:
SELECT nama, LENGTH(nama) AS jumlah_byte, CHAR_LENGTH(nama) AS jumlah_karakter
FROM produk
ORDER BY id;Output yang Dihasilkan:
+-------------------+-------------+-----------------+
| nama | jumlah_byte | jumlah_karakter |
+-------------------+-------------+-----------------+
| Buku Tulis 38 | 13 | 13 |
| Pensil 2B | 9 | 9 |
| Penggaris 30 cm | 15 | 15 |
| Spidol Whiteboard | 17 | 17 |
| Buku Gambar A4 | 14 | 14 |
| Kertas HVS A4 | 13 | 13 |
| Stipo Perekat | 17 | 17 |
| Penghapus | 9 | 9 |
+-------------------+-------------+-----------------+
8 rows in set (0.00 sec)Pada seluruh baris di atas kedua kolom bernilai sama karena nama produk hanya memuat huruf Latin standar — satu karakter memakai satu byte di pengodean utf8mb4. Perbedaannya baru terlihat pada karakter di luar ASCII dasar, misalnya huruf beraksen seperti é yang disimpan sebagai dua byte:
SELECT LENGTH('café') AS byte_cafe, CHAR_LENGTH('café') AS karakter_cafe;Output yang Dihasilkan:
+-----------+---------------+
| byte_cafe | karakter_cafe |
+-----------+---------------+
| 5 | 4 |
+-----------+---------------+
1 row in set (0.00 sec)Teks 'café' terdiri atas empat karakter, tetapi LENGTH melaporkan lima byte karena huruf é memakai dua byte. Untuk membatasi panjang input pengguna, CHAR_LENGTH biasanya lebih sesuai dengan yang dimaksud manusia; LENGTH lebih relevan saat menghitung ukuran penyimpanan.
Memotong Teks: SUBSTRING, LEFT, dan RIGHT #
SUBSTRING(teks, posisi, panjang) mengambil potongan mulai posisi tertentu, dengan posisi karakter pertama dihitung dari 1. LEFT() dan RIGHT() adalah bentuk singkat untuk mengambil potongan dari masing-masing ujung:
SELECT SUBSTRING('Belajar MySQL', 9, 5) AS potongan,
LEFT('Belajar MySQL', 7) AS dari_kiri,
RIGHT('Belajar MySQL', 5) AS dari_kanan;Output yang Dihasilkan:
+----------+-----------+------------+
| potongan | dari_kiri | dari_kanan |
+----------+-----------+------------+
| MySQL | Belajar | MySQL |
+----------+-----------+------------+
1 row in set (0.00 sec)Argumen 9 pada SUBSTRING berarti mulai dari karakter kesembilan (huruf M), lalu 5 berarti ambil lima karakter — hasilnya MySQL. LEFT(..., 7) mengambil tujuh karakter pertama Belajar, dan RIGHT(..., 5) mengambil lima karakter terakhir. Versi penerapan pada data tabel: mengambil tiga huruf pertama nama produk sebagai singkatan:
SELECT nama, LEFT(nama, 3) AS singkatan
FROM produk
ORDER BY id;Output yang Dihasilkan:
+-------------------+-----------+
| nama | singkatan |
+-------------------+-----------+
| Buku Tulis 38 | Buk |
| Pensil 2B | Pen |
| Penggaris 30 cm | Pen |
| Spidol Whiteboard | Spi |
| Buku Gambar A4 | Buk |
| Kertas HVS A4 | Ker |
| Stipo Perekat | S |
| Penghapus | Pen |
+-------------------+-----------+
8 rows in set (0.00 sec)Mencari dan Mengganti Teks: LOCATE dan REPLACE #
LOCATE(needle, haystack) mengembalikan posisi pertama teks yang dicari, dengan nilai 0 bila tidak ditemukan. REPLACE(teks, lama, baru) mengganti seluruh kemunculan lama dengan baru:
SELECT LOCATE('Pensil', 'Belajar Pensil 2B') AS posisi,
REPLACE('bunga-bunga', 'bunga', 'roti') AS diganti;Output yang Dihasilkan:
+--------+-----------+
| posisi | diganti |
+--------+-----------+
| 9 | roti-roti |
+--------+-----------+
1 row in set (0.00 sec)Posisi 9 berarti teks Pensil ditemukan mulai karakter kesembilan. Pada fungsi REPLACE, kedua kemunculan bunga sama-sama diganti sehingga hasilnya roti-roti. Satu kejutan yang sering menjebak pemula: dengan collation default MySQL yang tidak peka huruf besar-kecil, LOCATE juga menemukan mysql di dalam 'Belajar MySQL':
SELECT LOCATE('MySQL', 'Belajar MySQL') AS peka_huruf,
LOCATE('mysql', 'Belajar MySQL') AS tanpa_huruf_besar;Output yang Dihasilkan:
+------------+-------------------+
| peka_huruf | tanpa_huruf_besar |
+------------+-------------------+
| 9 | 9 |
+------------+-------------------+
1 row in set (0.00 sec)Kedua pencarian mengembalikan 9. Perilaku ini bukan bug — collation utf8mb4_0900_ai_ci memang membandingkan teks secara case-insensitive, dan fungsi pembanding teks mengikuti collation kolom atau literal yang dipakai.
Merapikan dan Melengkapi Teks: TRIM dan PAD #
TRIM() membuang spasi di kedua ujung teks, LTRIM() hanya di kiri, RTRIM() hanya di kanan. LPAD() menambah pengisi di kiri sampai teks mencapai panjang tertentu, RPAD() mengisi dari kanan:
SELECT nama, LENGTH(nama) AS panjang_kotor, TRIM(nama) AS nama_bersih,
LENGTH(TRIM(nama)) AS panjang_bersih
FROM produk
WHERE id = 7;Output yang Dihasilkan:
+-------------------+---------------+---------------+----------------+
| nama | panjang_kotor | nama_bersih | panjang_bersih |
+-------------------+---------------+---------------+----------------+
| Stipo Perekat | 17 | Stipo Perekat | 13 |
+-------------------+---------------+---------------+----------------+
1 row in set (0.00 sec)Baris dengan id = 7 ( Stipo Perekat ) punya empat byte spasi berlebih yang hilang setelah TRIM. Kita melihat pengukurannya lewat LENGTH, bukan CHAR_LENGTH, karena spasi tetap satu byte sehingga keduanya akan menunjukkan angka yang sama. Variasi lainnya memangkas hanya satu sisi — LTRIM kiri saja, RTRIM kanan saja:
SELECT LTRIM(' kiri ') AS buang_kiri, RTRIM(' kanan ') AS buang_kanan;Output yang Dihasilkan:
+------------+-------------+
| buang_kiri | buang_kanan |
+------------+-------------+
| kiri | kanan |
+------------+-------------+
1 row in set (0.00 sec)Hasil buang_kiri menyisakan spasi kanan, dan buang_kanan menyisakan spasi kiri — masing-masing hanya membersihkan satu sisi. Untuk pola pengisian, contoh klasiknya adalah kode barang tiga digit yang diawali nol:
SELECT id, LPAD(id, 3, '0') AS kode_barang, RPAD(UPPER(LEFT(nama, 2)), 5, '*') AS stiker
FROM produk
ORDER BY id;Output yang Dihasilkan:
+----+-------------+--------+
| id | kode_barang | stiker |
+----+-------------+--------+
| 1 | 001 | BU*** |
| 2 | 002 | PE*** |
| 3 | 003 | PE*** |
| 4 | 004 | SP*** |
| 5 | 005 | BU*** |
| 6 | 006 | KE*** |
| 7 | 007 | *** |
| 8 | 008 | PE*** |
+----+-------------+--------+
8 rows in set (0.00 sec)LPAD(id, 3, '0') menambah karakter 0 di sisi kiri sampai total panjangnya tiga — id 1 menjadi 001. Blok kedua juga menunjukkan bahwa fungsi string boleh bersarang: UPPER(LEFT(nama, 2)) mengambil dua karakter pertama nama lalu mengkapitalkannya, dan RPAD melengkapinya dengan tanda * sampai panjang lima.
Peta Ringkas Fungsi String #
| Fungsi | Kegunaan |
|---|---|
UPPER / LOWER | Mengubah seluruh huruf menjadi kapital / kecil |
CONCAT / CONCAT_WS | Menggabungkan teks, versi kedua memakai pemisah dan melewati NULL |
LENGTH / CHAR_LENGTH | Menghitung byte / jumlah karakter |
SUBSTRING | Mengambil potongan mulai posisi tertentu |
LEFT / RIGHT | Mengambil potongan dari ujung kiri / kanan |
LOCATE | Mencari posisi pertama sebuah teks (0 bila tidak ada) |
REPLACE | Mengganti seluruh kemunculan sebuah teks |
TRIM / LTRIM / RTRIM | Membuang spasi di ujung, kiri, atau kanan |
LPAD / RPAD | Menambah pengisi sampai panjang tertentu |
Membersihkan Database Latihan #
DROP DATABASE belajar_fungsi;Output yang Dihasilkan:
Query OK, 1 row affected (0.00 sec)Database belajar_fungsi dan tabel produk kini hilang dari server latihan. Fungsi string mengolah teks, namun query nyata juga penuh perhitungan angka — diskon, stok, pembagian. Chapter berikutnya membahas fungsi numerik: pembulatan dengan ROUND dan TRUNCATE, CEIL versus FLOOR, MOD, pangkat, serta perilaku pembagian yang berbeda dari kebanyakan bahasa pemrograman.