Bạn có thể đơn giản hóa ở một số chỗ (giả sử acct_id
và parent_id
là NOT NULL
):
WITH RECURSIVE search_graph AS (
SELECT parent_id, ARRAY[acct_id] AS path
FROM account
UNION ALL
SELECT g.parent_id, sg.path || g.acct_id
FROM search_graph sg
JOIN account g ON g.acct_id = sg.parent_id
WHERE g.acct_id <> ALL(sg.path)
)
SELECT path[1] AS child
, path[array_upper(path,1)] AS parent
, path
FROM search_graph
ORDER BY path;
- Các cột
acct_id
,depth
,cycle
chỉ là tiếng ồn trong truy vấn của bạn. -
WHERE
điều kiện phải thoát khỏi đệ quy sớm hơn một bước, trước mục nhập trùng lặp từ nút trên cùng nằm trong kết quả. Đó là "điểm khác biệt" trong bản gốc của bạn.
Phần còn lại là định dạng.
Nếu bạn biết vòng tròn duy nhất có thể có trong biểu đồ của bạn là tự tham chiếu, chúng tôi có thể có vòng tròn đó rẻ hơn:
WITH RECURSIVE search_graph AS (
SELECT parent_id, ARRAY[acct_id] AS path, acct_id <> parent_id AS keep_going
FROM account
UNION ALL
SELECT g.parent_id, sg.path || g.acct_id, g.acct_id <> g.parent_id
FROM search_graph sg
JOIN account g ON g.acct_id = sg.parent_id
WHERE sg.keep_going
)
SELECT path[1] AS child
, path[array_upper(path,1)] AS parent
, path
FROM search_graph
ORDER BY path;
SQL Fiddle.
Lưu ý rằng sẽ có vấn đề (ít nhất là tối đa pg v9.4) đối với các loại dữ liệu có công cụ sửa đổi (như varchar(5)
) vì nối mảng làm mất công cụ sửa đổi nhưng rCTE nhấn mạnh vào các loại khớp chính xác:
- Kết quả đáng ngạc nhiên cho các loại dữ liệu có công cụ sửa đổi loại