PostgreSQL → Advanced Statements
Sumber: Luca Ferrari, Enrico Pirozzi - Learn PostgreSQL Use, manage, and build secure and scalable databases with PostgreSQL 16 (2023) - Chapter 5
Pernyataan Lanjutan
Pada bab sebelumnya, kita telah memulai langkah pertama dengan PostgreSQL. Dalam bab ini, kita akan menganalisis bahasa SQL secara lebih mendalam dan menulis kueri yang lebih kompleks. Kita akan kembali membahas pernyataan SELECT, INSERT, dan UPDATE, tetapi kali ini dengan opsi yang lebih canggih. Selanjutnya, kita akan membahas join, Common Table Expressions (CTE), dan MERGE secara mendalam.
Berikut adalah topik yang akan kita pelajari dalam bab ini:
Mengeksplorasi pernyataan SELECT
Menggunakan UPSERT dan MERGE
Mengeksplorasi CTE
Persyaratan Teknis
Sebelum memulai, pastikan untuk menjalankan container Docker bernama chapter_05 dengan perintah berikut:
$ bash run-pg-docker.sh chapter_05
postgres@learn_postgresql:~$ psql -U forum forumdbMengeksplorasi Pernyataan SELECT
Seperti yang telah kita pelajari pada bab sebelumnya, pernyataan SELECT dapat digunakan untuk memfilter dataset menggunakan kondisi kesamaan. Selain itu, kita juga dapat memfilter data menggunakan kondisi > atau <, seperti pada contoh berikut:
forumdb=> select * from categories where pk > 2;
pk | title | description
----+----------------------+---------------------------------
3 | Programming Languages | All about programming languages
(1 row)Kueri di atas mengembalikan semua catatan dengan nilai pk > 2. Selain itu, kita juga dapat menggunakan kondisi LIKEuntuk memfilter data. Mari kita lihat lebih lanjut.
Menggunakan Klausa LIKE
Misalkan kita ingin mencari semua catatan yang memiliki nilai kolom title diawali dengan string Prog. Untuk melakukannya, kita dapat menggunakan kondisi LIKE:
Kueri di atas mengembalikan semua catatan dengan nilai title yang diawali dengan Prog. Jika kita ingin mencari catatan dengan title yang diakhiri dengan Languages, kita dapat menulis:
Kita juga dapat menggabungkan kedua jenis pencarian tersebut. Misalnya, untuk mencari catatan yang mengandung substring discuss pada kolom description:
Sekarang, coba jalankan kueri berikut:
Kueri ini tidak mengembalikan hasil karena pencarian dengan LIKE bersifat case-sensitive. Untuk mengatasi ini, kita dapat menggunakan fungsi upper(text), yang mengubah semua karakter dalam string menjadi huruf besar:
Di PostgreSQL, kita dapat memanggil fungsi tanpa menulis FROM, tidak seperti di Oracle yang memerlukan tabel dummy seperti DUAL. Untuk melakukan pencarian LIKE yang tidak peka huruf besar-kecil, kita dapat menulis:
Menggunakan ILIKE
PostgreSQL menyediakan operator ILIKE untuk melakukan pencarian LIKE yang tidak peka huruf besar-kecil:
Ini adalah cara PostgreSQL untuk menangani pencarian LIKE yang tidak peka huruf besar-kecil.
Menggunakan DISTINCT
Sekarang kita akan membahas kueri DISTINCT. Pertama, mari kita kenalkan fungsi coalesce, yang sangat berguna bagi DBA. Fungsi coalesce mengembalikan nilai pertama yang bukan NULL dari dua atau lebih parameter:
Sekarang, mari kita sisipkan kategori baru:
Kemudian, atur tampilan NULL:
Lihat data dalam tabel categories:
Untuk mengganti nilai NULL pada kolom description dengan No description, kita dapat menggunakan coalesce:
Namun, nama kolom hasil dari coalesce menjadi coalesce, yang kurang ramah pengguna. Kita dapat menetapkan alias untuk kolom tersebut:
Jika alias mengandung spasi atau huruf besar, gunakan tanda kutip:
Sekarang, mari kita sisipkan catatan lain:
Lihat data yang diurutkan berdasarkan title:
Terdapat dua catatan dengan nilai Database. Untuk menampilkan hanya nilai unik, gunakan klausa DISTINCT:
Klausa DISTINCT mengembalikan hanya nilai yang berbeda. Namun, untuk tabel besar, DISTINCT dapat memperlambat kueri karena melibatkan pengurutan data.
Menggunakan LIMIT dan OFFSET
Klausa LIMIT digunakan untuk membatasi jumlah baris yang dikembalikan, sedangkan OFFSET digunakan untuk melewati sejumlah baris tertentu. Keduanya dapat digunakan secara independen atau bersama-sama untuk mengembalikan sebagian data dari hasil kueri.
Contoh penggunaan LIMIT:
Kueri di atas mengembalikan hanya catatan pertama. Untuk dua catatan pertama:
Untuk mengambil catatan kedua saja:
LIMIT dan OFFSET sangat berguna untuk pengambilan data secara berhalaman. Selain itu, LIMIT dapat digunakan untuk membuat tabel baru dari struktur tabel yang ada:
Kueri ini menyalin hanya struktur data dari tabel categories ke new_categories:
Menggunakan Subkueri
Subkueri adalah kueri yang bersarang di dalam kueri lain menggunakan tanda kurung. Subkueri dapat mengembalikan nilai tunggal atau kumpulan catatan, seperti kueri biasa. Mari kita mulai dengan subkueri menggunakan operator IN/NOT IN.
Subkueri dengan Kondisi IN/NOT IN
Operator IN dapat digunakan di dalam klausa WHERE sebagai pengganti beberapa kondisi OR. Misalnya, untuk mencari kategori dengan pk=1 atau pk=2:
Alternatifnya, kita dapat menggunakan IN:
Operator NOT IN berfungsi sebaliknya, mencari catatan yang tidak memiliki nilai tertentu:
Sekarang, mari kita sisipkan data ke tabel users dan posts:
Lihat isi tabel posts:
Untuk mencari semua posting yang termasuk dalam kategori Database, kita dapat menggunakan subkueri:
Subkueri dalam kueri di atas adalah:
Subkueri ini mengambil nilai pk=1 dan pk=5 dari tabel categories, dan kueri utama mencari catatan di tabel posts yang memiliki category=1 atau category=5. Untuk mencari posting yang tidak termasuk dalam kategori Database:
Subkueri dengan Kondisi EXISTS/NOT EXISTS
Pernyataan EXISTS digunakan untuk memeriksa apakah subkueri mengembalikan hasil (TRUE), sedangkan NOT EXISTS memeriksa apakah subkueri tidak mengembalikan hasil (FALSE). Misalnya, untuk menulis ulang kueri sebelumnya menggunakan EXISTS:
Untuk mencari posting yang tidak termasuk dalam kategori Database menggunakan NOT EXISTS:
Kueri dengan IN dan EXISTS disebut kueri semi-join, dan kita akan membahas lebih lanjut tentang join di bagian berikutnya.
Mempelajari Join
Join adalah kombinasi baris dari dua atau lebih tabel. Misalnya, kueri berikut mengembalikan semua kombinasi baris dari tabel categories dan posts:
Kueri ini menghasilkan produk Cartesian antara tabel categories dan posts, yang juga disebut CROSS JOIN. Kueri yang sama dapat ditulis secara eksplisit sebagai:
Menggunakan INNER JOIN
Misalkan kita ingin memfilter baris yang memiliki nilai category yang sama (categories.pk = posts.category):
Kueri ini dapat ditulis menggunakan operasi INNER JOIN:
INNER JOIN memilih catatan yang memiliki nilai yang cocok di kedua tabel. Untuk mencari posting dalam kategori Database menggunakan INNER JOIN:
Kondisi INNER JOIN dapat digunakan untuk menulis ulang kueri yang menggunakan IN atau EXISTS, dan biasanya lebih cepat dalam hal kecepatan eksekusi.
Menggunakan LEFT JOIN
LEFT JOIN mengembalikan semua catatan dari tabel kiri (categories) dan catatan yang cocok dari tabel kanan (posts). Jika tidak ada kecocokan, hasilnya adalah NULL:
Untuk mencari kategori yang tidak memiliki posting:
Menggunakan RIGHT JOIN
RIGHT JOIN adalah kebalikan dari LEFT JOIN, mengembalikan semua catatan dari tabel kanan dan catatan yang cocok dari tabel kiri:
Hasilnya sama dengan LEFT JOIN jika tabel ditukar.
Menggunakan FULL OUTER JOIN
FULL OUTER JOIN menggabungkan hasil dari LEFT JOIN dan RIGHT JOIN:
Menggunakan LATERAL JOIN
LATERAL JOIN memungkinkan subkueri dijalankan untuk setiap baris dari tabel utama. Misalnya, tambahkan kolom likes ke tabel posts:
Untuk mencari pengguna dengan posting yang memiliki likes > 2:
Dengan LATERAL JOIN, kita juga dapat mengambil nilai likes:
Fungsi Agregasi
Fungsi agregasi melakukan perhitungan pada sekumpulan baris dan mengembalikan satu baris. PostgreSQL menyediakan fungsi agregasi standar SQL:
AVG(): Mengembalikan nilai rata-rata.
COUNT(): Mengembalikan jumlah nilai.
MAX(): Mengembalikan nilai maksimum.
MIN(): Mengembalikan nilai minimum.
SUM(): Mengembalikan jumlah nilai.
Fungsi agregasi digunakan bersama klausa GROUP BY, yang membagi hasil menjadi kelompok. Misalnya, untuk menghitung jumlah catatan per kategori:
Kita juga dapat menggunakan HAVING untuk memfilter kelompok:
Alias dapat digunakan pada fungsi agregasi, tetapi tidak pada klausa HAVING:
UNION/UNION ALL
Operator UNION menggabungkan hasil dari dua atau lebih pernyataan SELECT dengan syarat:
Jumlah kolom harus sama.
Tipe data kolom harus serupa.
Urutan kolom harus sama.
Contoh:
UNION ALL menyertakan duplikat:
EXCEPT/INTERSECT
Operator EXCEPT mengembalikan baris dari kueri pertama yang tidak ada di kueri kedua:
Operator INTERSECT mengembalikan baris yang ada di kedua kueri:
Menggunakan UPSERT
UPSERT (Update or Insert) digunakan untuk menyisipkan catatan baru atau memperbarui catatan yang sudah ada. Di PostgreSQL, ini dilakukan dengan ON CONFLICT:
Contoh:
Menggunakan DO UPDATE:
Klausa RETURNING untuk INSERT
Klausa RETURNING mengembalikan nilai kolom setelah INSERT:
Memperbarui Catatan Terkait
Untuk memperbarui catatan yang terkait dengan beberapa tabel:
MERGE
Mulai dari PostgreSQL 15, MERGE dapat digunakan untuk memperbarui atau menyisipkan data:
Mengeksplorasi UPDATE ... RETURNING
Klausa RETURNING juga dapat digunakan pada UPDATE:
Mengeksplorasi DELETE ... RETURNING
Klausa RETURNING juga tersedia untuk DELETE:
Mengeksplorasi CTE
Common Table Expression (CTE) adalah hasil sementara dari pernyataan SQL, yang dapat berisi SELECT, INSERT, UPDATE, atau DELETE. Masa hidup CTE sama dengan masa hidup kueri. Contoh definisi CTE:
Contoh CTE untuk mencari posting oleh penulis tertentu:
Alternatifnya, kita dapat menggunakan inline view:
CTE di PostgreSQL Sejak Versi 12
Mulai dari PostgreSQL 12, opsi MATERIALIZED dan NOT MATERIALIZED diperkenalkan. Contoh dengan MATERIALIZED:
Dengan NOT MATERIALIZED:
Jika tidak ditentukan, defaultnya adalah NOT MATERIALIZED, yang dapat memengaruhi performa saat migrasi dari versi sebelumnya.
Kasus Penggunaan CTE
Contoh penggunaan CTE:
Buat dua tabel baru:
Pindahkan catatan yang dihapus dari
t_postskedelete_posts:
Hasilnya:
Contoh lain, pindahkan semua catatan dari
t_postskeinserted_posts:
Kueri Rekursif
PostgreSQL mendukung kueri rekursif, yang berguna untuk basis data graf atau struktur pohon. CTE rekursif memungkinkan pernyataan tambahan mereferensikan dirinya sendiri.
Contoh:
Peringatan: Hindari loop tak terbatas dalam CTE rekursif dengan memastikan rekursi berhenti dengan benar.
Ringkasan
Bab ini membahas kueri kompleks, termasuk pernyataan SELECT dengan klausa LIKE, ILIKE, DISTINCT, OFFSET, LIMIT, IN, dan NOT IN. Kita juga mempelajari agregasi dengan GROUP BY dan HAVING, serta fungsi agregasi seperti SUM(), COUNT(), AVG(), MIN(), dan MAX(). Selain itu, kita menjelajahi subkueri, berbagai jenis join, serta pernyataan UNION, EXCEPT, dan INTERSECT. Terakhir, kita membahas opsi lanjutan untuk INSERT, DELETE, UPDATE, dan MERGE, serta kekuatan CTE dalam PostgreSQL.
Pada bab berikutnya, kita akan mempelajari cara membuat agregasi menggunakan window functions, yang memungkinkan pembuatan agregasi baru dengan lebih fleksibel.
Last updated