Lompati ke konten utama
Modul 5 · Pelajaran 2 dari 418/57 dalam kursus~10 min
Pelajaran modul (2/4)

Self-JOIN: meja dengan dirinya sendiri

Terkadang hubungan yang ingin Anda lewati bukan di antara keduanya tabel yang berbeda, tetapi di antara baris tabel yang sama. Contoh tipikal: a hierarki "kategori → subkategori", dengan induk dan anak berada dalam baris tabel categories yang sama, dihubungkan oleh parent_id.

Untuk membaca bersama satu baris (anak) dan baris lainnya (induk) "nya", Anda menggunakan a bergabung sendiri: tabel yang sama muncul dua kali di FROM, dengan dua alias yang berbeda.

Sintaksnya

SQL
SELECT colonne
FROM   tabella AS alias_a
JOIN   tabella AS alias_b ON alias_a.foreign_key = alias_b.id;

Alias wajib: jika kita menghilangkan AS a / AS b, PostgreSQL tidak memiliki cara untuk mengetahui salinan mana yang kita maksud ketika kita menulis name atau id.

SQL
-- Ogni sotto-categoria con il nome della categoria padre:
SELECT child.name  AS subcategory,
       parent.name AS category
FROM   categories AS child
JOIN   categories AS parent ON child.parent_id = parent.id;

Baca dalam bahasa Inggris sederhana: "ambil baris categories bernama child, dan untuk masing-masingnya carilah baris categories bernama induk yang id-nya adalah parent_id anak".

Hasilnya tidak termasuk kategori akar (kategori dengan parent_id = NULL) karena INNER JOIN melewatkan baris yang tidak cocok. Jika Anda ingin menyertakan mereka, gunakan LEFT JOIN.

Gabung sendiri dengan LEFT untuk "menjaga akarnya juga"

SQL
-- Tutte le categorie, con nome del padre o NULL se sono radice:
SELECT child.name AS category,
       parent.name AS parent
FROM   categories AS child
LEFT JOIN categories AS parent ON child.parent_id = parent.id;

Sekarang Anda mendapatkan 9 baris (setiap kategori dalam kumpulan data), dengan parent = NULL untuk 3 akar.

Bergabung dengan bergabung sendiri

Ini sangat cocok dipadukan dengan GROUP BY untuk menanyakan "berapa banyak anak yang melakukan masing-masing anak orang tua punya":

SQL
SELECT p.name AS parent_category,
       COUNT(c.id) AS children
FROM   categories AS p
LEFT JOIN categories AS c ON c.parent_id = p.id
WHERE  p.parent_id IS NULL          -- solo le radici
GROUP BY p.name
ORDER BY p.name;

Perhatikan dua detail penting:

  1. WHERE p.parent_id IS NULL memfilter sebelum GABUNG: kami hanya mengambil akar sebagai "tabel sebelah kiri".
  2. COUNT(c.id) (bukan COUNT(*)) mengembalikan 0 untuk akar tanpa anak, sedangkan COUNT(*) akan menghasilkan 1 karena baris LEFT JOIN dengan BATAL.

Cobalah sendiri

Latihan#sql.m5.l2.e1
Upaya: 0Memuat…

Untuk semua kategori ini (kategori dengan parent_id NOT NULL), tampilkan nama dari kategori-kategori tersebut dan nama dari kategori-kategori tersebut. Karena titik dua: subkategori, kategori. Urutan per kategori poi per subkategori.

Memuat editor…
Tunjukkan petunjuk

Kondisi self-JOIN adalah child.parent_id = parent.id.

Solusi tersedia setelah 3 upaya

Tinjau latihan

Latihan#sql.m5.l2.e2
Upaya: 0Memuat…

Untuk setiap kategori-radice (parent_id IS NULL), tampilkan nama dan nomor dari sotto-categorie. Karena colonne: nama, anak-anak. Ordina per nama. Termasuk sebuah hasil akhirnya tanpa gambar dengan 0.

Memuat editor…
Tunjukkan petunjuk

LEFT JOIN pada kategori dua kali (alias p untuk orang tua, c untuk anak). Gunakan COUNT(c.id), bukan COUNT(*), untuk mendapatkan 0 pada root tanpa anak.

Solusi tersedia setelah 3 upaya