Chapter Fungsi Konversi Tipe Data memperkenalkan dua sintaks konversi: CAST(x AS tipe) dan singkatan x::tipe. Sekarang kita masuk lebih dalam: kapan PostgreSQL mengonversi tipe secara otomatis di belakang layar, kapan konversi harus ditulis eksplisit, dan di mana letak jebakannya. Aturan ini menjelaskan banyak pesan error yang tadinya terasa misterius — misalnya mengapa INSERT menerima string '29.5' untuk kolom numeric, tetapi SELECT 'lima' + 3 ditolak mentah-mentah.

Konteks Assignment dan Konteks Eksplisit #

PostgreSQL membedakan dua konteks konversi. Konteks assignment terjadi ketika nilai dipindahkan ke “wadah” yang tipenya sudah ditentukan — kolom tabel, argument function, atau variable di PL/pgSQL. Pada konteks ini, PostgreSQL mengonversi tipe secara implisit selama konversinya dianggap aman. Konteks eksplisit adalah sisanya: ekspresi bebas seperti SELECT '5' + 3, di mana tidak ada wadah yang menentukan tipe tujuan, sehingga konversi harus kita tulis sendiri.

Berikut demonstrasi keduanya berdampingan:

sql cast-dasar.sql
SELECT CAST('2026-01-15' AS date) AS tanggal;

SELECT '5'::integer + 3 AS hasil_cast;

SELECT 42::text || ' adalah jawaban' AS teks;

Output yang Dihasilkan:

text
  tanggal   
------------
 2026-01-15
(1 row)

 hasil_cast 
------------
          8
(1 row)

       teks        
-------------------
 42 adalah jawaban
(1 row)

Mari kita bedah ketiganya:

  1. CAST('2026-01-15' AS date): bentuk standar SQL. Teks diubah menjadi date sebelum bisa dibandingkan atau dihitung dengan kolom tanggal lain.
  2. '5'::integer + 3: sintaks khusus PostgreSQL (lebih pendek, sama kuatnya). Tanpa cast, '5' + 3 gagal karena text + integer tidak punya operator.
  3. 42::text || ' adalah jawaban': arah sebaliknya — angka menjadi teks supaya bisa digabung dengan ||, karena integer || text juga tidak punya operator.

Konversi Implisit di Konteks Assignment #

Untuk melihat konversi implisit bekerja, kita perlu sebuah tabel. File berikut membuat tabel suhu, mengisi dua baris dengan angka biasa, lalu — perhatikan pernyataan ketiga — menyisipkan '29.5' sebagai teks ke kolom numeric:

CREATE TABLE suhu (
    id     integer PRIMARY KEY,
    kota   text NOT NULL,
    celsius numeric(5, 2) NOT NULL
);

INSERT INTO suhu (id, kota, celsius) VALUES
    (1, 'Jakarta', 31.5),
    (2, 'Bandung', 23.0);

INSERT INTO suhu (id, kota, celsius) VALUES (3, 'Denpasar', '29.5');

SELECT id, kota, celsius, celsius::integer AS bulat
FROM suhu
ORDER BY id;

Output yang Dihasilkan:

text
CREATE TABLE
INSERT 0 2
INSERT 0 1
 id |   kota   | celsius | bulat 
----+----------+---------+-------
  1 | Jakarta  |   31.50 |    32
  2 | Bandung  |   23.00 |    23
  3 | Denpasar |   29.50 |    30
(3 rows)

Tiga fakta dari hasil di atas:

  1. INSERT ketiga sukses: string literal '29.5' berada di konteks assignment (tujuannya kolom numeric), sehingga PostgreSQL mengonversinya diam-diam menjadi 29.50. Nilai yang tersimpan dan ditampilkan pun sudah numerik.
  2. Hasil 29.5 tampil sebagai 29.50: kolom numeric(5,2) menyimpan tepat dua desimal — skala tipe yang menentukan, bukan bentuk teks masukan.
  3. celsius::integer membulatkan: cast dari numeric ke integer membulatkan ke bilangan terdekat — 31.50 menjadi 32, 23.00 menjadi 23 — bukan memotong seperti pembagian integer.

Perbedaan konteks ini juga menjelaskan kenapa WHERE tanggal BETWEEN '2026-01-01' AND '2026-03-31' pada chapter BETWEEN bisa berjalan tanpa cast: operator BETWEEN dengan operand date di satu sisi membuat literal teks di sisi lainnya dikonversi di konteks assignment.

Ketika Konversi Gagal #

Konversi implisit maupun eksplisit sama-sama menolak nilai yang tidak bisa ditafsirkan sebagai tipe tujuan. Pesan errornya menyebut nilai bermasalah dan tipe tujuan:

SELECT CAST('limabelas' AS integer);

Output yang Dihasilkan:

text
psql:konversi-gagal.sql:1: ERROR:  invalid input syntax for type integer: "limabelas"
LINE 1: SELECT CAST('limabelas' AS integer);
                    ^

Pesan invalid input syntax for type integer: "limabelas" berarti teks lolos tahap parsing, tetapi saat konversi ke integer karakter-karakternya tidak membentuk angka yang valid. Karena konversi berlangsung saat query berjalan — bukan saat data disimpan — kesalahan seperti ini sering baru terasa pada data kotor: kolom teks yang seharusnya berisi angka tetapi berisi satu baris "limabelas" akan membuat kolom::integer gagal untuk seluruh query.

Konversi yang Mungkin Mengejutkan #

Beberapa pasangan tipe bisa dicast padahal tidak terduga. Angka ke boolean mengikuti aturan “nol berarti salah”; teks ke boolean menerima banyak literal bahasa Inggris:

SELECT 1::boolean AS satu_benar,
       0::boolean AS nol_salah,
       'yes'::boolean AS ya_benar,
       'off'::boolean AS mati_salah;

Output yang Dihasilkan:

text
 satu_benar | nol_salah | ya_benar | mati_salah 
------------+-----------+----------+------------
 t          | f         | t        | f
(1 row)

Tabel berikut merangkum literal boolean yang diterima PostgreSQL saat casting teks:

TeksNilai boolean
'true', 't', 'yes', 'y', 'on', '1'true
'false', 'f', 'no', 'n', 'off', '0'false

Perhatikan bahwa 'benar' tidak termasuk daftar — teks bahasa Indonesia ditolak dengan error invalid input syntax for type boolean, sebagaimana sudah dibuktikan di Section Tipe Data. Casting antar dua representasi yang sama-sama valid ini berguna saat mengimpor data dari sistem lain yang menyimpan flag sebagai angka 0/1.

Cast ke Tipe Terstruktur #

Cast tidak berhenti di tipe skalar. Teks yang terformat dengan benar bisa langsung menjadi jsonb, dan teks array menjadi tipe array asli PostgreSQL:

SELECT '{"nama": "Budi", "stok": 12}'::jsonb AS dokumen;

SELECT ('{' || '"teh", ' || '"kopi"' || '}')::text[] AS daftar;

Output yang Dihasilkan:

text
           dokumen            
------------------------------
 {"nama": "Budi", "stok": 12}
(1 row)

   daftar   
------------
 {teh,kopi}
(1 row)

Dua pengamatan dari output di atas:

  1. Cast ke jsonb mem-parse teks JSON sekaligus menormalkannya: urutan kunci dipertahankan sesuai asal teks, spasi berlebih dibuang, dan hasilnya siap diindeks serta diquery dengan operator -> dan @> (materi Section JSON dan Data Semi-Terstruktur).
  2. Cast ke text[] pada pernyataan kedua membangun literal array secara dinamis dengan ||, lalu mengubahnya menjadi array satu dimensi — teknik yang berguna saat menyusun array dari bagian-bagian teks. Teks sumbernya harus mengikuti format literal array PostgreSQL: kurung kurawal di kedua ujung dan tiap elemen dikutip.

Kebiasaan Casting yang Sehat #

Tiga kebiasaan merangkum seluruh chapter ini. Pertama, andalkan konteks assignment untuk kasus yang jelas — INSERT dan perbandingan dengan kolom bertipe sudah menangani konversi literal dengan aman. Kedua, tulis cast eksplisit pada ekspresi bebas; sintaks :: ringkas dan idiomatik PostgreSQL, sedangkan CAST(... AS ...) lebih mudah dipindahkan ke database lain karena keduanya identik secara perilaku. Ketiga, curigai data kotor: cast teks-ke-angka pada kolom buatan pengguna sebaiknya didampingi validasi atau penanganan error, bukan dipasang telanjang.

Dengan peta operator, ekspresi, dan casting yang kini lengkap, kita siap memasuki salah satu bagian paling praktis dari SQL sehari-hari: merangkum data dengan agregasi — diawali chapter COUNT pada Section Agregasi Data.

Referensi #

Berkas Sumber

Berkas pendukung halaman ini dapat diunduh dan dijalankan langsung sesuai penjelasan di atas.

cast-dasar.sql

Unduh berkas
sql
SELECT CAST('2026-01-15' AS date) AS tanggal;

SELECT '5'::integer + 3 AS hasil_cast;

SELECT 42::text || ' adalah jawaban' AS teks;

cast-ke-jsonb.sql

Unduh berkas
sql
SELECT '{"nama": "Budi", "stok": 12}'::jsonb AS dokumen;

SELECT ('{' || '"teh", ' || '"kopi"' || '}')::text[] AS daftar;

konteks-implisit.sql

Unduh berkas
sql
CREATE TABLE suhu (
    id     integer PRIMARY KEY,
    kota   text NOT NULL,
    celsius numeric(5, 2) NOT NULL
);

INSERT INTO suhu (id, kota, celsius) VALUES
    (1, 'Jakarta', 31.5),
    (2, 'Bandung', 23.0);

INSERT INTO suhu (id, kota, celsius) VALUES (3, 'Denpasar', '29.5');

SELECT id, kota, celsius, celsius::integer AS bulat
FROM suhu
ORDER BY id;

konversi-boolean.sql

Unduh berkas
sql
SELECT 1::boolean AS satu_benar,
       0::boolean AS nol_salah,
       'yes'::boolean AS ya_benar,
       'off'::boolean AS mati_salah;

konversi-gagal.sql

Unduh berkas
sql
SELECT CAST('limabelas' AS integer);