ORDER BY dan LIMIT

Mengurutkan hasil query dan membatasi jumlah baris untuk keperluan paginasi.

Daftar isi

Topik ini membahas dua klausa yang hampir selalu menyertai query pembacaan data, yaitu ORDER BY untuk mengurutkan hasil dan LIMIT untuk membatasi jumlah baris. Blok penyiapan membangun ulang dataset perpustakaan yang sama, sehingga setiap urutan dan pemotongan pada topik ini dapat diulang persis. Setelah topik ini, pembaca mampu menyusun daftar terurut, mengambil halaman tertentu, dan memahami mengapa urutan selalu dinyatakan eksplisit.

Blok penyiapan dataset#

bash
# 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);
SQL

Mengurutkan dengan ORDER BY#

Hasil query tanpa ORDER BY tidak memiliki urutan yang dijanjikan, meskipun pada praktiknya sering terlihat berurutan menurut id. Klausa ORDER BY menyatakan urutan secara eksplisit, dengan ASC sebagai arah bawaan dan DESC untuk arah terbalik. Query berikut mendaftar buku dari tahun terbit paling baru.

bash
# buku dari tahun terbit paling baru
psql -U postgres -d perpustakaan -c "SELECT judul, tahun FROM buku ORDER BY tahun DESC;"
text Keluaran
            judul            | tahun
-----------------------------+-------
 Cerita Kota Lama            |  2023
 Kimia Organik               |  2022
 Statistika Terapan          |  2022
 Dasar Basis Data            |  2021
 Algoritma dan Struktur Data |  2021
 Fisika untuk Pemula         |  2020
 Jaringan Komputer           |  2019
 Sejarah Nusantara           |  2018
(8 rows)

Dua buku terbit 2022 dan dua lagi terbit 2021, dan urutan di antara keempat baris itu tidak dijanjikan oleh query ini. Setiap penyebutan ORDER BY dengan kunci yang seri harus ditindaklanjuti dengan kunci pemutus, yang menjadi pembahasan bagian ketiga topik ini.

Kunci kedua sebagai pemutus seri#

ORDER BY menerima lebih dari satu kunci yang dinilai berurutan, sehingga kunci kedua hanya bekerja pada baris yang nilainya seri pada kunci pertama. Query berikut mengurutkan menurut tahun terbit menurun, lalu menurut judul menaik sebagai pemutusnya.

bash
# tahun menurun, judul menaik sebagai pemutus seri
psql -U postgres -d perpustakaan -c "SELECT judul, tahun FROM buku ORDER BY tahun DESC, judul ASC;"
text Keluaran
            judul            | tahun
-----------------------------+-------
 Cerita Kota Lama            |  2023
 Kimia Organik               |  2022
 Statistika Terapan          |  2022
 Algoritma dan Struktur Data |  2021
 Dasar Basis Data            |  2021
 Fisika untuk Pemula         |  2020
 Jaringan Komputer           |  2019
 Sejarah Nusantara           |  2018
(8 rows)

Perbandingannya dengan keluaran sebelumnya terlihat pada tahun 2021, di mana Algoritma dan Struktur Data kini muncul lebih dahulu karena urutan abjadnya. Pola dua kunci ini berlaku berantai untuk sebanyak mungkin kunci yang dibutuhkan.

Membatasi baris dengan LIMIT dan OFFSET#

Klausa LIMIT mengambil sejumlah baris pertama dari hasil yang sudah terurut, dan OFFSET melewati sejumlah baris sebelum mulai mengambil. Kombinasi keduanya membangun paginasi, yaitu halaman pertama berisi baris 1 sampai 5 dan halaman kedua mulai dari baris keenam.

bash
# halaman pertama: lima buku terbaru
psql -U postgres -d perpustakaan -c "SELECT judul, tahun FROM buku ORDER BY tahun DESC, judul LIMIT 5;"
text Keluaran
            judul            | tahun
-----------------------------+-------
 Cerita Kota Lama            |  2023
 Kimia Organik               |  2022
 Statistika Terapan          |  2022
 Algoritma dan Struktur Data |  2021
 Dasar Basis Data            |  2021
(5 rows)
bash
# halaman kedua: lewati lima baris pertama
psql -U postgres -d perpustakaan -c "SELECT judul, tahun FROM buku ORDER BY tahun DESC, judul LIMIT 5 OFFSET 5;"
text Keluaran
        judul        | tahun
---------------------+-------
 Fisika untuk Pemula |  2020
 Jaringan Komputer   |  2019
 Sejarah Nusantara   |  2018
(3 rows)

Halaman kedua hanya berisi tiga baris karena data tinggal segitu, dan tidak ada error untuk pemotongan yang melebihi jumlah baris. OFFSET tanpa LIMIT sah secara sintaks, tetapi jarang berguna karena seluruh baris setelah titik lompatannya ikut dikembalikan.

Mengapa urutan harus eksplisit#

Perencana PostgreSQL bebas memilih cara mengambil baris, dan urutan baca fisiknya dapat berubah mengikuti index, paralelisme, dan isi cache. Dua eksekusi query yang sama tanpa ORDER BY dapat menghasilkan urutan berbeda tanpa menjadi salah. Konsekuensinya, setiap query yang hasilnya disajikan kepada manusia atau dibandingkan antar eksekusi wajib membawa ORDER BY yang lengkap sampai kuncinya memutus semua seri.

Kebiasaan yang aman menambahkan kunci pemutus yang unik, misalnya id, sebagai kunci terakhir. Pada dataset kecil, kelalaian ini tampak tidak berbahaya karena urutannya kebetulan stabil, sedangkan pada data yang tumbuh, keanehan urutan muncul dan sulit dilacak.

Kesalahan umum#

Kesalahan pertama adalah memakai OFFSET untuk paginasi besar, misalnya halaman ke-500 dengan OFFSET 2495. Query tetap harus melewati seluruh baris sebelum titik lompatan, sehingga biayanya tumbuh seiring halaman, dan penggantinya berbasis kursor dibahas pada modul index dan performa. Kesalahan kedua adalah LIMIT tanpa ORDER BY, yang menghasilkan baris mana pun lima buah, bukan lima buah terbaru atau teratas.

Kesalahan ketiga adalah mengurutkan menurut kolom yang tidak ada pada SELECT dan mengira itu salah. ORDER BY bekerja pada kolom tabel dan ekspresi, bukan hanya kolom hasil, sehingga ORDER BY id pada query yang tidak menyebut id sepenuhnya sah dan berguna sebagai pemutus seri.

Ringkasan#

  • Tanpa ORDER BY, urutan hasil tidak dijanjikan, sehingga urutan selalu dinyatakan secara eksplisit.
  • Kunci kedua dan seterusnya memutus baris yang seri pada kunci sebelumnya, dan kunci unik seperti id menjadi pemutus yang aman.
  • LIMIT membatasi jumlah baris dan OFFSET melewatinya, sehingga keduanya membangun paginasi sederhana.
  • OFFSET besar membayar biaya penyisiran yang tumbuh, dan kursor menjadi penggantinya pada beban yang besar.

Referensi#