Pada kebanyakan database, INTEGER adalah kontrak yang keras: masukkan teks ke kolom integer dan database menolaknya. SQLite memilih jalan lain — kolom bertipe tetap, tetapi engine berusaha menyesuaikan nilai yang masuk dengan konversi otomatis. Perilaku ini bernama type affinity, dan memahaminya adalah kunci untuk tidak terkejut oleh data yang tersimpan dalam bentuk tak terduga. Chapter ini membedah aturan mainnya, semuanya diverifikasi langsung dengan fungsi typeof().
Lima Storage Class #
Di level paling dasar, SQLite hanya mengenal lima storage class — bentuk penyimpanan nilai di dalam berkas database:
| Storage class | Isi | Contoh literal |
|---|---|---|
NULL | Nilai kosong | NULL |
INTEGER | Bilangan bulat | 42 |
REAL | Bilangan pecahan | 3.14 |
TEXT | Teks | 'Budi' |
BLOB | Data mentah | x'89504E47' |
Fungsi typeof() melaporkan storage class dari nilai atau isi kolom. Kita bisa mencobanya langsung pada nilai literal:
sqlite> SELECT typeof(NULL), typeof(42), typeof(3.14), typeof('Budi'), typeof(x'89504E47');
null|integer|real|text|blob
sqlite>Yang mengejutkan pemula SQLite: tipe kolom seperti INTEGER atau TEXT di statement CREATE TABLE bukanlah penjara. Fungsi tipe kolom hanyalah rekomendasi konversi, dan rekomendasi itulah yang disebut type affinity.
Aturan Type Affinity #
Saat sebuah nilai dimasukkan ke kolom, engine SQLite menentukan konversinya dari tipe yang kita tulis saat membuat tabel. Aturannya diperiksa berurutan — aturan pertama yang cocok menang:
- Nama tipe mengandung
INT→ affinity INTEGER. - Nama tipe mengandung
CHAR,CLOB, atauTEXT→ affinity TEXT. - Nama tipe
BLOBatau tidak bertipe sama sekali → affinity BLOB. - Nama tipe mengandung
REAL,FLOA, atauDOUB→ affinity REAL. - Nama tipe lainnya → affinity NUMERIC.
Dua nama tipe yang sering mengejutkan: VARCHAR(10) dan CHAR(10) sama-sama mengandung CHAR, jadi keduanya beraffinity TEXT — bukan numerik. Sebaliknya DECIMAL(10,2) tidak memuat satu pun kata kunci di atas, jadi jatuh ke affinity NUMERIC. Tabel berikut merangkum pemetaan yang paling sering dipakai:
| Deklarasi kolom | Affinity | Contoh lain |
|---|---|---|
INT, INTEGER, BIGINT | INTEGER | SMALLINT, TINYINT |
TEXT, CHAR(10), VARCHAR(255) | TEXT | CLOB |
BLOB, tanpa tipe | BLOB | — |
REAL, FLOAT, DOUBLE PRECISION | REAL | DOUBLE |
DECIMAL(10,2), BOOLEAN, DATE | NUMERIC | NUMERIC |
Affinity inilah yang menentukan apa yang sebenarnya tersimpan. Mari kita buktikan dengan satu tabel uji berisi tiga kolom beraffinity berbeda:
sqlite> CREATE TABLE uji (
...> a INTEGER,
...> b REAL,
...> c TEXT
...> );
sqlite> INSERT INTO uji VALUES ('10', 2, 100);
sqlite> SELECT typeof(a), typeof(b), typeof(c) FROM uji;
integer|real|text
sqlite>Satu statement INSERT ini memuat tiga kejutan sekaligus:
- Kolom
a INTEGERdiisi string'10'— affinity INTEGER mengonversi teks yang membentuk bilangan bulat menjadi integer, sehingga yang tersimpan adalah integer10. - Kolom
b REALdiisi bilangan bulat2— affinity REAL mengubahnya menjadi pecahan2.0. - Kolom
c TEXTdiisi bilangan bulat100— affinity TEXT mengubahnya menjadi teks'100'.
Affinity NUMERIC berperilaku seperti INTEGER bila bisa: '10' menjadi integer 10 dan '3.14' menjadi real 3.14. Teks yang tak bisa dikonversi tetap disimpan sebagai teks — tanpa error:
sqlite> CREATE TABLE uji2 (n NUMERIC);
sqlite> INSERT INTO uji2 VALUES ('10'), ('3.14'), ('Budi');
sqlite> SELECT n, typeof(n) FROM uji2;
10|integer
3.14|real
Budi|text
sqlite>STRICT untuk Pengetikan yang Kaku #
Jika fleksibilitas ini justru berbahaya bagi aplikasi kita, SQLite sejak versi 3.37.0 menyediakan mode ketat: tambahkan kata STRICT setelah kurung penutup CREATE TABLE. Pada STRICT table, tipe kolom wajib salah satu dari INT, INTEGER, REAL, TEXT, BLOB, atau ANY — nama lain seperti VARCHAR(10) langsung ditolak.
sqlite> CREATE TABLE produk_strict (
...> id INTEGER PRIMARY KEY,
...> nama TEXT NOT NULL,
...> harga INTEGER NOT NULL
...> ) STRICT;
sqlite> INSERT INTO produk_strict VALUES (1, 'Pensil', 3000);
sqlite> INSERT INTO produk_strict VALUES (2, 'Buku Tulis', 'murah');
Runtime error: cannot store TEXT value in INTEGER column produk_strict.harga (19)
sqlite>Insert kedua ditolak keras: teks 'murah' tidak mungkin dikonversi menjadi integer tanpa kehilangan makna. Teks yang membentuk angka sah — misalnya '5500' — tetap diterima karena konversinya lossless, tetapi teks sembarangan tidak lolos. Pilihan antara tabel biasa dan STRICT tabel sepenuhnya ada di tangan kita: tabel biasa mewarisi fleksibilitas khas SQLite, sedangkan STRICT memberi perilaku yang segerak dengan PostgreSQL atau MySQL.
Bagaimana pun jenis tabel yang kita pilih, struktur kolom saja belum cukup menjaga kualitas data — kolom nama masih boleh kosong dan dua baris produk masih boleh bernama sama. Chapter Constraint pada Tabel melengkapi pertahanan itu.