PostgreSQL
 sql >> Cơ Sở Dữ Liệu >  >> RDS >> PostgreSQL

Tự tham gia đệ quy Postgresql

Đây là cách sử dụng cổ điển của một biểu thức bảng chung đệ quy đơn giản (WITH RECURSIVE ), có sẵn trong PostgreSQL 8.4 trở lên.

Minh họa tại đây:http://sqlfiddle.com/#!12/78e15/9

Đưa ra dữ liệu mẫu dưới dạng SQL:

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

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

Bạn có thể viết:

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;

Điều này làm là đi lặp lại chuỗi, thêm từng hàng vào chain bảng dưới dạng con trỏ từ và tới. Khi nó gặp một hàng mà tham chiếu 'to' không tồn tại, nó sẽ thêm tham chiếu null 'to' cho hàng đó. Lần lặp tiếp theo sẽ nhận thấy rằng tham chiếu 'to' là null và tạo ra hàng không, điều này khiến quá trình lặp kết thúc.

Sau đó, truy vấn bên ngoài sẽ chọn các hàng đã được xác định là phần cuối của chuỗi bằng cách có một to_id không tồn tại.

Cần một chút nỗ lực để tìm hiểu về CTE đệ quy. Những điều quan trọng cần hiểu là:

  • Chúng bắt đầu với đầu ra của một truy vấn ban đầu, mà chúng liên tục kết hợp với đầu ra của "phần đệ quy" (truy vấn sau UNION hoặc UNION ALL ) cho đến khi phần đệ quy thêm không có hàng. Điều đó sẽ ngừng lặp lại.

  • Chúng không thực sự đệ quy, lặp đi lặp lại nhiều hơn, mặc dù chúng tốt cho các loại thứ bạn có thể sử dụng đệ quy.

Vì vậy, về cơ bản bạn đang xây dựng một bảng trong một vòng lặp. Bạn không thể xóa hoặc thay đổi các hàng, chỉ thêm những hàng mới, vì vậy, bạn thường cần một truy vấn bên ngoài lọc kết quả để nhận được các hàng kết quả bạn muốn. Bạn sẽ thường thêm các cột bổ sung chứa dữ liệu trung gian mà bạn sử dụng để theo dõi trạng thái của quá trình lặp lại, kiểm soát các điều kiện dừng, v.v.

Nó có thể hữu ích khi xem xét kết quả chưa được lọc. Nếu tôi thay thế truy vấn tóm tắt cuối cùng bằng chuỗi SELECT * FROM chain Tôi có thể thấy bảng đã được tạo:

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

Hàng đầu tiên là hàng điểm bắt đầu được thêm theo cách thủ công, nơi bạn chỉ định những gì bạn muốn tra cứu - trong trường hợp này là vc2 . Mỗi hàng tiếp theo được thêm bởi UNION ed thuật ngữ đệ quy, thực hiện LEFT OUTER JOIN trên kết quả trước đó và trả về một tập hợp các hàng mới ghép nối với to_id trước đó (hiện có trong from_id cột) đến to_id tiếp theo . Nếu LEFT OUTER JOIN không khớp thì to_id sẽ là null, khiến lệnh gọi tiếp theo trả về các hàng hiện tại và kết thúc lặp lại.

Bởi vì truy vấn này không cố gắng chỉ thêm cuối cùng hàng mỗi lần, nó thực sự lặp lại một chút công việc mỗi lần lặp lại. Để tránh điều đó, bạn sẽ cần phải sử dụng cách tiếp cận giống như của Gordon hơn, nhưng bổ sung lọc trên trường độ sâu trước đó khi bạn quét bảng đầu vào, vì vậy bạn chỉ tham gia hàng gần đây nhất. Trong thực tế, điều này thường không cần thiết, nhưng nó có thể là mối lo ngại đối với các tập dữ liệu rất lớn hoặc nơi bạn không thể tạo các chỉ mục thích hợp.

Có thể tìm hiểu thêm trong tài liệu PostgreSQL về 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. Nhiều CTE trong một truy vấn

  2. Cách cài đặt Haproxy và Keepalived

  3. Có cách nào để thực thi truy vấn bên trong giá trị chuỗi (như eval) trong PostgreSQL không?

  4. Tên bảng JPA viết hoa

  5. Người dùng Postgres không tồn tại?