Chapter INSERT sudah mengisi tabel produk dengan enam baris data; sekarang saatnya mengambil data itu kembali. Perintah SELECT adalah operasi database yang paling sering kita jalankan — laporan, tampilan aplikasi, analisis, semuanya bermuara ke satu perintah ini. Pada chapter ini kita fokus pada fondasinya: memilih kolom mana yang ingin dilihat, memberi nama alias pada hasil, menghitung nilai baru langsung di dalam SELECT, lalu menyusun hasil agar tampil dalam urutan yang pasti.

Menyiapkan Tabel Latihan #

Supaya setiap contoh bisa dijalankan sendiri, kita buat ulang tabel produk — kali ini dengan satu kolom tambahan deskripsi yang boleh NULL, karena kolom itu akan memperlihatkan perilaku tampilan nilai NULL:

sql buat-tabel.sql
CREATE TABLE produk (
    id        integer PRIMARY KEY,
    nama      text NOT NULL,
    kategori  text NOT NULL,
    harga     numeric(10, 2) NOT NULL,
    deskripsi text
);

INSERT INTO produk (id, nama, kategori, harga, deskripsi) VALUES
    (1, 'Buku Tulis', 'alat tulis', 4500, 'Buku 58 halaman bergaris'),
    (2, 'Pulpen Hitam', 'alat tulis', 3000, NULL),
    (3, 'Kertas HVS A4', 'kertas', 55000, 'Kertas 70 gram'),
    (4, 'Stapler Besar', 'alat tulis', 24000, NULL),
    (5, 'Amplop Coklat', 'kertas', 1500, NULL),
    (6, 'Penghapus', 'alat tulis', 2000, 'Penghapus putih');

Output yang Dihasilkan:

text
CREATE TABLE
INSERT 0 6

Struktur tabel ini sama dengan tabel di chapter INSERT, hanya kolom deskripsi yang baru — dan tiga baris sengaja dibiarkan tanpa deskripsi (NULL). Nilai NULL bukan string kosong; NULL berarti “tidak ada nilainya sama sekali”, dan perbedaan itu akan terlihat di output sebentar lagi.

Memilih Kolom yang Ditampilkan #

Bentuk paling sederhana SELECT menentukan dua hal: kolom apa yang ingin dilihat, dan dari tabel mana datanya diambil. Tanda bintang (*) berarti “semua kolom”:

sql pilih-kolom.sql
SELECT * FROM produk ORDER BY id;

SELECT nama, harga FROM produk ORDER BY id;

Output yang Dihasilkan:

text
 id |     nama      |  kategori  |  harga   |        deskripsi         
----+---------------+------------+----------+--------------------------
  1 | Buku Tulis    | alat tulis |  4500.00 | Buku 58 halaman bergaris
  2 | Pulpen Hitam  | alat tulis |  3000.00 | 
  3 | Kertas HVS A4 | kertas     | 55000.00 | Kertas 70 gram
  4 | Stapler Besar | alat tulis | 24000.00 | 
  5 | Amplop Coklat | kertas     |  1500.00 | 
  6 | Penghapus     | alat tulis |  2000.00 | Penghapus putih
(6 rows)

     nama      |  harga   
---------------+----------
 Buku Tulis    |  4500.00
 Pulpen Hitam  |  3000.00
 Kertas HVS A4 | 55000.00
 Stapler Besar | 24000.00
 Amplop Coklat |  1500.00
 Penghapus     |  2000.00
(6 rows)

Dua hal penting dari hasil tersebut:

  1. SELECT * mengembalikan semua kolom dalam urutan definisi tabel — lima kolom termasuk id dan deskripsi. Praktik ini enak untuk eksplorasi, tetapi di kode aplikasi sebaiknya sebutkan kolom secara eksplisit: kebutuhan transfer data lebih kecil, dan perintah tidak diam-diam berubah perilaku saat struktur tabel berubah.
  2. SELECT nama, harga hanya membawa dua kolom itu — kolom lain tetap tersimpan di tabel, hanya tidak ikut ditampilkan.

Perhatikan kolom deskripsi pada hasil pertama: baris Pulpen Hitam, Stapler Besar, dan Amplop Coklat menampilkan sel kosong. Itulah cara psql menampilkan NULL — bukan string kosong ' ', melainkan benar-benar tidak ada nilai. Tanda kosong dan string kosong terlihat sama di layar, sehingga pembeda keduanya perlu operator IS NULL, yang dibahas tuntas di chapter IS NULL pada Section Filtering dan Sorting.

Klausa ORDER BY id pada kedua perintah sengaja dipasang sejak awal: tanpa ORDER BY, PostgreSQL tidak menjamin urutan baris hasil sama sekali. Baris biasanya keluar sesuai urutan penyimpanan, tetapi itu kebetulan implementasi, bukan janji standar SQL.

Alias: Mengganti Nama Kolom Hasil #

Nama kolom seperti harga memang sudah jelas, tetapi hasil perhitungan atau hasil dari tabel yang di-JOIN sering butuh nama yang lebih manusiawi. Alias mengganti judul kolom di hasil — perubahan murni tampilan, tabel aslinya tidak tersentuh:

SELECT nama AS nama_produk, harga harga_rupiah
FROM produk
ORDER BY id;

SELECT nama,
       harga * 1.1 AS "Harga Setelah Naik"
FROM produk
ORDER BY id;

Output yang Dihasilkan:

text
  nama_produk  | harga_rupiah 
---------------+--------------
 Buku Tulis    |      4500.00
 Pulpen Hitam  |      3000.00
 Kertas HVS A4 |     55000.00
 Stapler Besar |     24000.00
 Amplop Coklat |      1500.00
 Penghapus     |      2000.00
(6 rows)

     nama      | Harga Setelah Naik 
---------------+--------------------
 Buku Tulis    |           4950.000
 Pulpen Hitam  |           3300.000
 Kertas HVS A4 |          60500.000
 Stapler Besar |          26400.000
 Amplop Coklat |           1650.000
 Penghapus     |           2200.000
(6 rows)

Mari kita bedah tiga variasi alias pada contoh di atas:

  1. nama AS nama_produk — bentuk paling eksplisit dengan kata kunci AS. Judul kolom hasil berubah menjadi nama_produk.
  2. harga harga_rupiah — kata AS boleh dihilangkan; cukup kolom diikuti nama alias. Kedua bentuk identik hasilnya, dan memilih salah satunya selera gaya tim.
  3. harga * 1.1 AS "Harga Setelah Naik" — alias dua kata atau alias dengan karakter khusus (spasi, kurung, huruf besar campuran) wajib dibungkus kutip dua. Tanpa kutip, PostgreSQL memperlakukan Harga dan Setelah sebagai dua identifier terpisah dan menolak perintahnya.

Alias pada kolom hasil juga berguna bagi aplikasi: driver database di PHP, Go, atau Python memakai nama kolom hasil sebagai kunci array/map, dan nama yang deskriptif membuat kode pembaca hasil jauh lebih bersih.

Ekspresi di Dalam SELECT #

Daftar kolom tidak terbatas pada kolom tabel — setiap ekspresi yang sah boleh ditempatkan di sana: aritmetika, penggabungan string dengan operator ||, pemanggilan function, sampai CASE. Perhitungan terjadi per baris, sehingga hasilnya tetap sebaris dengan data aslinya. Contoh kedua di file sebelumnya sudah memperlihatkan harga * 1.1; berikut variasi yang menggabungkan dua operasi sekaligus:

SELECT nama, harga
FROM produk
ORDER BY harga DESC, nama
LIMIT 3;

Output yang Dihasilkan:

text
     nama      |  harga   
---------------+----------
 Kertas HVS A4 | 55000.00
 Stapler Besar | 24000.00
 Buku Tulis    |  4500.00
(3 rows)

Perintah ini menggabungkan tiga teknik sekaligus:

  1. ORDER BY harga DESC, nama mengurutkan berdasarkan harga dari yang termahal (DESC = descending), dengan nama sebagai pemecah seri bila dua harga sama — kombinasi ini menjamin urutan hasil selalu identik di mesin mana pun.
  2. LIMIT 3 memotong hasil menjadi tiga baris pertama. Pola ORDER BY ... LIMIT n adalah resep dasar query “top-N”: produk termahal, pelanggan terbaru, lima penjualan terbesar. Pembahasan lengkapnya ada di chapter LIMIT dan OFFSET.
  3. DESC hanya berlaku pada kolom yang dilekatinya — nama tetap naik (A ke Z) karena tidak diberi DESC.

Membedakan Nilai Unik dengan DISTINCT #

Kolom kategori hanya berisi dua nilai berbeda, tetapi enam baris menampilkannya berulang. DISTINCT menghilangkan baris hasil yang sama persis:

SELECT kategori FROM produk ORDER BY kategori, id;

SELECT DISTINCT kategori FROM produk ORDER BY kategori;

Output yang Dihasilkan:

text
  kategori  
------------
 alat tulis
 alat tulis
 alat tulis
 alat tulis
 kertas
 kertas
(6 rows)

  kategori  
------------
 alat tulis
 kertas
(2 rows)

Perintah pertama mengembalikan enam baris (satu per produk), perintah kedua hanya dua baris: alat tulis dan kertas. DISTINCT bekerja pada seluruh baris hasil — bila dua kolom dipilih, baris duplikat dianggap sama hanya ketika kedua kolomnya identik. Kombinasi DISTINCT dengan ORDER BY juga penting: hasil DISTINCT tanpa ORDER BY tidak menjamin urutan, dan kita membutuhkan urutan yang pasti agar output latihan ini reproducible. Pemanfaatan DISTINCT yang lebih dalam — DISTINCT ON, interaksi dengan agregasi — dibahas di chapter DISTINCT pada Section Filtering dan Sorting.

SELECT Tanpa FROM: Kalkulator Cepat #

SELECT tanpa klausa FROM mengevaluasi ekspresi begitu saja dan mengembalikan satu baris. PostgreSQL menjadi kalkulator yang selalu tersedia di terminal:

sql tanpa-from.sql
SELECT 2 + 3 AS hasil;

SELECT 'Halo, ' || 'PostgreSQL' AS sapaan;

Output yang Dihasilkan:

text
 hasil 
-------
     5
(1 row)

      sapaan      
------------------
 Halo, PostgreSQL
(1 row)

Bentuk ini berguna untuk menguji expression sebelum dipakai di query besar: format tanggal, operasi string, atau perilaku NULL — sama seperti kita menguji 2 + 3 untuk membuktikan bahwa PostgreSQL memang benar-benar menghitung, bukan sekadar mengembalikan teks perintah. Bila Anda sempat mencoba SELECT 2 + 3; di chapter INSERT saat memverifikasi koneksi, bentuk inilah yang Anda jalankan.

Satu catatan penutup tentang proses keseluruhan: SELECT tidak pernah memindahkan data keluar dari tabel — server membaca baris, menghitung ekspresi per baris, lalu mengirim hasil ke klien. Tabel tetap utuh; yang berubah hanya tampilan. Berbeda dengan tiga operasi berikutnya, mulai dari UPDATE, yang benar-benar menimpa nilai di dalam tabel — dan di sanalah kehati-hatian mulai menjadi urusan serius.

Referensi #

Berkas Sumber

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

alias-dan-ekspresi.sql

Unduh berkas
sql
SELECT nama AS nama_produk, harga harga_rupiah
FROM produk
ORDER BY id;

SELECT nama,
       harga * 1.1 AS "Harga Setelah Naik"
FROM produk
ORDER BY id;

buat-tabel.sql

Unduh berkas
sql
CREATE TABLE produk (
    id        integer PRIMARY KEY,
    nama      text NOT NULL,
    kategori  text NOT NULL,
    harga     numeric(10, 2) NOT NULL,
    deskripsi text
);

INSERT INTO produk (id, nama, kategori, harga, deskripsi) VALUES
    (1, 'Buku Tulis', 'alat tulis', 4500, 'Buku 58 halaman bergaris'),
    (2, 'Pulpen Hitam', 'alat tulis', 3000, NULL),
    (3, 'Kertas HVS A4', 'kertas', 55000, 'Kertas 70 gram'),
    (4, 'Stapler Besar', 'alat tulis', 24000, NULL),
    (5, 'Amplop Coklat', 'kertas', 1500, NULL),
    (6, 'Penghapus', 'alat tulis', 2000, 'Penghapus putih');

distinct-preview.sql

Unduh berkas
sql
SELECT kategori FROM produk ORDER BY kategori, id;

SELECT DISTINCT kategori FROM produk ORDER BY kategori;

pilih-kolom.sql

Unduh berkas
sql
SELECT * FROM produk ORDER BY id;

SELECT nama, harga FROM produk ORDER BY id;

tanpa-from.sql

Unduh berkas
sql
SELECT 2 + 3 AS hasil;

SELECT 'Halo, ' || 'PostgreSQL' AS sapaan;

urutkan-batas.sql

Unduh berkas
sql
SELECT nama, harga
FROM produk
ORDER BY harga DESC, nama
LIMIT 3;