PostgreSQL
 sql >> Teknologi Basis Data >  >> RDS >> PostgreSQL

Gabung mandiri rekursif Postgresql

Ini adalah penggunaan klasik dari ekspresi tabel umum rekursif sederhana (WITH RECURSIVE ), tersedia di PostgreSQL 8.4 dan yang lebih baru.

Ditunjukkan di sini:http://sqlfiddle.com/#!12/78e15/9

Diberikan contoh data sebagai SQL:

CREATE TABLE Table1
    ("ID1" text, "ID2" text)
;

INSERT INTO Table1
    ("ID1", "ID2")
VALUES
    ('vc1', 'vc2'),
    ('vc2', 'vc3'),
    ('vc3', 'vc4'),
    ('vc4', 'rc7')
;

Anda dapat menulis:

WITH RECURSIVE chain(from_id, to_id) AS (
  SELECT NULL, 'vc2'
  UNION
  SELECT c.to_id, t."ID2"
  FROM chain c
  LEFT OUTER JOIN Table1 t ON (t."ID1" = to_id)
  WHERE c.to_id IS NOT NULL
)
SELECT from_id FROM chain WHERE to_id IS NULL;

Apa yang dilakukan adalah menjalankan rantai secara iteratif, menambahkan setiap baris ke chain tabel sebagai dari- dan ke-pointer. Ketika menemukan baris yang referensi 'ke' tidak ada, ia akan menambahkan referensi 'ke' nol untuk baris itu. Iterasi berikutnya akan melihat bahwa referensi 'ke' adalah null dan menghasilkan baris nol, yang menyebabkan iterasi berakhir.

Kueri luar kemudian mengambil baris yang telah ditentukan sebagai akhir rantai dengan memiliki to_id yang tidak ada.

Dibutuhkan sedikit usaha untuk memahami CTE rekursif. Hal-hal penting yang harus dipahami adalah:

  • Mereka mulai dengan output dari kueri awal, yang berulang kali mereka gabungkan dengan output dari "bagian rekursif" (kueri setelah UNION atau UNION ALL ) sampai bagian rekursif tidak menambahkan baris. Itu menghentikan iterasi.

  • Mereka tidak benar-benar rekursif, lebih berulang, meskipun mereka bagus untuk hal-hal yang mungkin Anda gunakan untuk rekursi.

Jadi pada dasarnya Anda membuat tabel dalam satu lingkaran. Anda tidak dapat menghapus baris atau mengubahnya, hanya menambahkan baris baru, jadi Anda biasanya memerlukan kueri luar yang memfilter hasil untuk mendapatkan baris hasil yang Anda inginkan. Anda akan sering menambahkan kolom tambahan yang berisi data perantara yang Anda gunakan untuk melacak status iterasi, mengontrol kondisi berhenti, dll.

Ini dapat membantu untuk melihat hasil tanpa filter. Jika saya mengganti kueri ringkasan akhir dengan sederhana SELECT * FROM chain Saya dapat melihat tabel yang telah dibuat:

 from_id | to_id 
---------+-------
         | vc2
 vc2     | vc3
 vc3     | vc4
 vc4     | rc7
 rc7     | 
(5 rows)

Baris pertama adalah baris titik awal yang ditambahkan secara manual, tempat Anda menentukan apa yang ingin Anda cari - dalam hal ini adalah vc2 . Setiap baris berikutnya ditambahkan oleh UNION ed istilah rekursif, yang melakukan LEFT OUTER JOIN pada hasil sebelumnya dan mengembalikan serangkaian baris baru yang memasangkan to_id . sebelumnya (sekarang di from_id kolom) ke to_id berikutnya . Jika LEFT OUTER JOIN tidak cocok maka to_id akan menjadi null, menyebabkan pemanggilan berikutnya mengembalikan baris sekarang dan mengakhiri iterasi.

Karena kueri ini tidak mencoba menambahkan hanya terakhir baris setiap kali, itu sebenarnya mengulangi sedikit pekerjaan yang adil setiap iterasi. Untuk menghindarinya, Anda perlu menggunakan pendekatan yang lebih mirip dengan Gordon, tetapi filter tambahan pada bidang kedalaman sebelumnya saat Anda memindai tabel input, jadi Anda hanya bergabung dengan baris terbaru. Dalam praktiknya, hal ini biasanya tidak diperlukan, tetapi dapat menjadi masalah untuk kumpulan data yang sangat besar atau jika Anda tidak dapat membuat indeks yang sesuai.

Lebih banyak dapat dipelajari di dokumentasi PostgreSQL di CTE.



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. PostgreSQL buat tabel jika tidak ada

  2. Menggunakan beberapa skema PostgreSQL dengan model Rails

  3. Ketidakcocokan Openshift dan net-ssh? (2.9.3-beta1 vs 2.9.2)

  4. Solusi DBaaS Terbaik untuk PostgreSQL

  5. Perintah pengembalian baris SQL