CTE: Nhận tất cả cha mẹ và tất cả trẻ em trong một tuyên bố


10

Tôi có ví dụ CTE làm việc này.

Tôi có thể chọn tất cả cha mẹ lớn và tất cả trẻ em.

Nhưng làm thế nào tôi có thể chọn tất cả cha mẹ lớn và tất cả trẻ em trong một tuyên bố?

Trong ví dụ này, tôi muốn Ông, Cha, Con làm đầu ra nếu tôi cho "Cha" làm đầu vào.

Tôi sử dụng PostgreSQL. Nhưng tôi nghĩ câu hỏi này phải là SQL chuẩn.

Vui lòng sửa cho tôi nếu tôi sử dụng cú pháp cụ thể của PostgreSQL.

DROP table if exists tree;

CREATE TABLE tree (
 id SERIAL PRIMARY KEY,
 name character varying(64) NOT NULL,
 parent_id integer REFERENCES tree NULL
);

insert into tree values (1, 'Grandfather', NULL);
insert into tree values (2, 'Father', 1);
insert into tree values (3, 'Son', 2);


-- -------------------------------------
-- Getting all children works  

WITH RECURSIVE rec (id) as
(
  SELECT tree.id, tree.name from tree where name='Father'

  UNION ALL

  SELECT tree.id, tree.name from rec, tree where tree.parent_id = rec.id



  )
SELECT *
FROM rec;

-- Result: 
--  id |  name  
-- ----+--------
--   2 | Father
--   3 | Son



-- -------------------------------------
-- Getting all parents works

WITH RECURSIVE rec (id) as
(
  SELECT tree.id, tree.name, tree.parent_id from tree where name='Father'

  UNION ALL

  SELECT tree.id, tree.name, tree.parent_id from rec, tree where tree.id = rec.parent_id
  )
SELECT id, name
FROM rec;

-- Result
-- id |    name     
-- ----+-------------
--  2 | Father
--  1 | Grandfather

Cập nhật

Trên đây là một ví dụ làm việc đơn giản hóa. Cây có thể sâu đến 100 cấp. Có thể có một số cấp độ của tổ tiên ở trên "Cha" và một số cấp độ con cháu bên dưới. Tôi muốn tất cả tổ tiên và tất cả con cháu.


@dezso đây chỉ là một ví dụ. Cây có thể sâu đến 100 cấp.
guettli

Câu trả lời:


15

Nếu bạn muốn tất cả tổ tiên và tất cả con cháu, bạn có thể kết hợp hai truy vấn trong một. Sử dụng hai CTE và sau đó đơn giản UNION:

WITH RECURSIVE 
    -- descendants 
    rec_d (id, name) AS
    (
      SELECT tree.id, tree.name FROM tree WHERE name = 'Father'
      UNION ALL
      SELECT tree.id, tree.name FROM rec_d, tree where tree.parent_id = rec_d.id
    ),
    --  ancestors
    rec_a (id, name, parent_id) AS
    (
      SELECT tree.id, tree.name, tree.parent_id FROM tree WHERE name = 'Father'
      UNION ALL
      SELECT tree.id, tree.name, tree.parent_id FROM rec_a, tree WHERE tree.id = rec_a.parent_id
    )
SELECT id, name FROM rec_a
UNION 
SELECT id, name FROM rec_d ;

Nếu chúng tôi không có bất kỳ lỗi nào ở trên, chúng tôi có thể cải thiện nó:

  • thay đổi cuối cùng UNIONthành UNION ALLbằng cách đặt (các) nút bắt đầu chỉ trong một trong các CTE.
  • sử dụng JOIN .. ONthay vì tham gia ngầm.
  • sửa lỗi không khớp giữa danh sách cột SELECT và CTE.

Truy vấn trở thành:

WITH RECURSIVE 
    -- starting node(s)
    starting (id, name, parent_id) AS
    (
      SELECT t.id, t.name, t.parent_id
      FROM tree AS t
      WHERE t.name = 'Father'          -- this can be arbitrary
    ),
    descendants (id, name, parent_id) AS
    (
      SELECT s.id, s.name, s.parent_id 
      FROM starting AS s
      UNION ALL
      SELECT t.id, t.name, t.parent_id 
      FROM tree AS t JOIN descendants AS d ON t.parent_id = d.id
    ),
    ancestors (id, name, parent_id) AS
    (
      SELECT t.id, t.name, t.parent_id 
      FROM tree AS t 
      WHERE t.id IN (SELECT parent_id FROM starting)
      UNION ALL
      SELECT t.id, t.name, t.parent_id 
      FROM tree AS t JOIN ancestors AS a ON t.id = a.parent_id
    )
TABLE ancestors
UNION ALL
TABLE descendants ;
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.