Topik ini menutup modul psql dan query pertama dengan dua kemampuan SELECT yang melengkapi penyaringan dan pengurutan, yaitu DISTINCT untuk menghilangkan duplikasi dan ekspresi untuk membentuk kolom hasil baru. Blok penyiapan membangun ulang dataset perpustakaan yang sama, sehingga setiap keluaran dapat diulang persis.
Blok penyiapan dataset#
# siapkan ulang tabel dan data contoh untuk topik ini
PGOPTIONS='-c client_min_messages=warning' psql -q -U postgres -d perpustakaan <<'SQL'
DROP TABLE IF EXISTS peminjaman, buku, anggota, kategori CASCADE;
CREATE TABLE kategori (id SERIAL PRIMARY KEY, nama TEXT NOT NULL UNIQUE);
CREATE TABLE anggota (id SERIAL PRIMARY KEY, nama TEXT NOT NULL, email TEXT UNIQUE, bergabung DATE NOT NULL, aktif BOOLEAN NOT NULL DEFAULT TRUE);
CREATE TABLE buku (id SERIAL PRIMARY KEY, judul TEXT NOT NULL, penulis TEXT NOT NULL, tahun INTEGER NOT NULL, kategori_id INTEGER REFERENCES kategori(id));
CREATE TABLE peminjaman (id SERIAL PRIMARY KEY, anggota_id INTEGER NOT NULL REFERENCES anggota(id), buku_id INTEGER NOT NULL REFERENCES buku(id), tanggal_pinjam DATE NOT NULL, tanggal_kembali DATE);
INSERT INTO kategori (nama) VALUES ('Pemrograman'), ('Sains'), ('Sejarah'), ('Fiksi'), ('Statistika');
INSERT INTO anggota (nama, email, bergabung, aktif) VALUES ('Ali Rahman', '[email protected]', '2024-01-15', TRUE), ('Budi Santoso', '[email protected]', '2024-03-02', TRUE), ('Citra Kirana', '[email protected]', '2024-05-20', FALSE), ('Dewi Lestari', '[email protected]', '2024-08-11', TRUE), ('Eka Pratama', NULL, '2025-01-30', TRUE);
INSERT INTO buku (judul, penulis, tahun, kategori_id) VALUES ('Dasar Basis Data', 'Sari Wulandari', 2021, 1), ('Jaringan Komputer', 'Ahmad Fauzi', 2019, 1), ('Fisika untuk Pemula', 'Rina Marlina', 2020, 2), ('Kimia Organik', 'Rina Marlina', 2022, 2), ('Sejarah Nusantara', 'Bambang Wijaya', 2018, 3), ('Cerita Kota Lama', 'Nur Aisyah', 2023, 4), ('Statistika Terapan', 'Sari Wulandari', 2022, 5), ('Algoritma dan Struktur Data', 'Ahmad Fauzi', 2021, 1);
INSERT INTO peminjaman (anggota_id, buku_id, tanggal_pinjam, tanggal_kembali) VALUES (1, 1, '2025-03-01', '2025-03-15'), (1, 7, '2025-03-05', '2025-03-20'), (2, 3, '2025-03-10', NULL), (3, 5, '2025-02-20', '2025-03-01'), (2, 1, '2025-04-02', NULL), (4, 6, '2025-04-07', NULL), (5, 8, '2025-04-09', '2025-04-25'), (4, 2, '2025-05-01', NULL);
SQLMenghilangkan duplikasi dengan DISTINCT#
Tabel buku memuat delapan baris, tetapi penulisnya hanya lima orang karena tiga orang menulis lebih dari satu buku. Kata DISTINCT pada SELECT menghilangkan baris yang seluruh kolom hasilnya sama dengan baris sebelumnya, sehingga daftar penulis menjadi unik.
# daftar penulis tanpa duplikasi
psql -U postgres -d perpustakaan -c "SELECT DISTINCT penulis FROM buku ORDER BY penulis;" penulis
----------------
Ahmad Fauzi
Bambang Wijaya
Nur Aisyah
Rina Marlina
Sari Wulandari
(5 rows)DISTINCT bekerja pada gabungan seluruh kolom yang disebut, bukan pada satu kolom pertamanya. Query SELECT DISTINCT penulis, tahun tetap menampilkan Rina Marlina dua kali karena kedua bukunya terbit pada tahun yang berbeda, dan perilaku ini harus dipahami sebelum memakai DISTINCT pada beberapa kolom sekaligus.
Ekspresi dan alias pada daftar kolom#
Setiap butir pada daftar SELECT boleh berupa ekspresi, bukan hanya kolom. Hasilnya menjadi kolom baru pada keluaran, dan kata AS memberinya nama alias yang mudah dirujuk. Query berikut menghitung umur buku dari tahun terbitnya terhadap tahun acuan 2025.
# umur buku terhadap tahun acuan 2025
psql -U postgres -d perpustakaan -c "SELECT judul, tahun, 2025 - tahun AS umur FROM buku ORDER BY umur DESC, judul LIMIT 4;" judul | tahun | umur
-----------------------------+-------+------
Sejarah Nusantara | 2018 | 7
Jaringan Komputer | 2019 | 6
Fisika untuk Pemula | 2020 | 5
Algoritma dan Struktur Data | 2021 | 4
(4 rows)Tanpa alias, kolom hasil ekspresi dinamai ?column? yang tidak bermakna, sehingga AS ditulis pada setiap kolom hasil hitungan. Alias dipakai ulang pada ORDER BY dan GROUP BY, tetapi tidak pada WHERE, keterbatasan yang dibahas pada bagian kesalahan umum.
Menggabungkan teks dengan operator ||#
Operator || menyambungkan dua teks menjadi satu, dan PostgreSQL menerapkannya juga pada nilai non-teks yang dikonversi secara otomatis. Query berikut membentuk label yang menyatukan penulis dengan tahun terbitnya.
# label penulis dan tahun dalam satu kolom
psql -U postgres -d perpustakaan -c "SELECT judul, penulis || ' (' || tahun || ')' AS penulisan FROM buku WHERE kategori_id = 1 ORDER BY judul;" judul | penulisan
-----------------------------+-----------------------
Algoritma dan Struktur Data | Ahmad Fauzi (2021)
Dasar Basis Data | Sari Wulandari (2021)
Jaringan Komputer | Ahmad Fauzi (2019)
(3 rows)Apabila salah satu sisi || bernilai NULL, seluruh hasilnya menjadi NULL, karena mengetahui sebagian saja dianggap tidak cukup untuk membentuk teks utuh. Fungsi concat() justru memperlakukan NULL sebagai teks kosong, dan pemilihan di antara keduanya bergantung pada makna yang diinginkan, dengan detail nilai NULL dibahas pada modul jenis data.
DISTINCT ON, kekhasan PostgreSQL#
PostgreSQL menyediakan bentuk DISTINCT ON (ekspresi) yang mempertahankan baris pertama dari setiap kelompok nilai sesuai ORDER BY. Query berikut mengambil satu buku terbaru untuk setiap penulis.
# satu buku terbaru per penulis
psql -U postgres -d perpustakaan -c "SELECT DISTINCT ON (penulis) penulis, judul, tahun FROM buku ORDER BY penulis, tahun DESC, judul;" penulis | judul | tahun
----------------+-----------------------------+-------
Ahmad Fauzi | Algoritma dan Struktur Data | 2021
Bambang Wijaya | Sejarah Nusantara | 2018
Nur Aisyah | Cerita Kota Lama | 2023
Rina Marlina | Kimia Organik | 2022
Sari Wulandari | Statistika Terapan | 2022
(5 rows)ORDER BY harus diawali ekspresi yang sama dengan DISTINCT ON agar baris yang dibandingkan bertetangga, dan kunci setelahnya menentukan baris pertama yang dipertahankan. Bentuk ini ringkas untuk kebutuhan per grup awal, sedangkan window function pada modul subquery dan CTE menawarkan kendali yang lebih luas.
Kesalahan umum#
Kesalahan pertama adalah merujuk alias di dalam WHERE, misalnya WHERE umur > 5 setelah mendefinisikannya pada SELECT. WHERE dinilai sebelum SELECT, sehingga aliasnya belum ada, dan yang benar adalah mengulang ekspresinya, yaitu WHERE 2025 - tahun > 5. Kesalahan kedua adalah memakai DISTINCT untuk menambal data ganda tanpa menyelidiki penyebabnya, padahal duplikasi yang sah berarti rancangan tabelnya perlu ditinjau.
Kesalahan ketiga adalah mengira DISTINCT membandingkan kolom pertama saja. Perbandingannya mencakup seluruh daftar kolom hasil, sehingga penambahan satu kolom dapat mengembalikan baris yang tadinya dianggap ganda. Ketiga kekeliruan ini terdeteksi cepat dengan membaca ulang keluaran yang jumlah barisnya tidak sesuai harapan.
Ringkasan#
- DISTINCT menghilangkan baris hasil yang seluruh kolomnya sama, dan bekerja pada gabungan seluruh kolom yang disebut.
- Ekspresi pada daftar SELECT membentuk kolom baru, dan alias AS memberinya nama yang dapat dirujuk pada klausa selain WHERE.
- Operator || menyambungkan teks, dengan seluruh hasil menjadi NULL apabila salah satu sisinya NULL.
- DISTINCT ON adalah kekhasan PostgreSQL untuk mengambil satu baris per kelompok, dengan syarat ORDER BY yang diawali ekspresinya.
Referensi#
- SELECT — PostgreSQL Documentation — Referensi resmi DISTINCT, DISTINCT ON, dan alias pada SELECT.
- String Functions and Operators — PostgreSQL Documentation — Dokumentasi operator || dan fungsi concat.
- Select Lists — PostgreSQL Documentation — Bab resmi tentang daftar kolom, ekspresi, dan penamaan hasil.