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

Truy vấn đệ quy Postgres với row_to_json

Xin lỗi vì câu trả lời rất muộn nhưng tôi nghĩ rằng tôi đã tìm thấy một giải pháp hữu ích có thể trở thành một câu trả lời được chấp nhận cho câu hỏi này.

Dựa trên "bản hack nhỏ" tuyệt vời được tìm thấy bởi @pozs, tôi đã đưa ra một giải pháp:

  • giải quyết tình huống "lá lừa đảo" với rất ít mã (tận dụng NOT EXISTS vị ngữ)
  • tránh toàn bộ công cụ tính toán / điều kiện cấp độ
WITH RECURSIVE customer_area_tree("id", "customer_id", "parent_id", "name", "description", "children") AS (
  -- tree leaves (no matching children)
  SELECT c.*, json '[]'
  FROM customer_area_node c
  WHERE NOT EXISTS(SELECT * FROM customer_area_node AS hypothetic_child WHERE hypothetic_child.parent_id = c.id)

  UNION ALL

  -- pozs's awesome "little hack"
  SELECT (parent).*, json_agg(child) AS "children"
  FROM (
    SELECT parent, child
    FROM customer_area_tree AS child
    JOIN customer_area_node parent ON parent.id = child.parent_id
  ) branch
  GROUP BY branch.parent
)
SELECT json_agg(t)
FROM customer_area_tree t
LEFT JOIN customer_area_node AS hypothetic_parent ON(hypothetic_parent.id = t.parent_id)
WHERE hypothetic_parent.id IS NULL

Cập nhật :

Được thử nghiệm với dữ liệu rất đơn giản, nó hoạt động, nhưng như posz đã chỉ ra trong một nhận xét, với dữ liệu mẫu của mình, một số nút lá giả mạo đã bị lãng quên. Nhưng, tôi phát hiện ra rằng với dữ liệu phức tạp hơn nữa, câu trả lời trước đó cũng không hoạt động, bởi vì chỉ các nút lá giả mạo có tổ tiên chung với các nút lá "cấp tối đa" mới bị bắt (khi "1.2.5.8" không có ở đó " 1.2.4 "và" 1.2.5 "vắng mặt vì chúng không có tổ tiên chung với bất kỳ nút lá" cấp tối đa "nào).

Vì vậy, đây là một đề xuất mới, trộn công việc của posz với của tôi bằng cách trích xuất NOT EXISTS yêu cầu con và biến nó thành UNION nội bộ , tận dụng UNION khả năng khử trùng lặp (tận dụng khả năng so sánh jsonb):

<!-- language: sql -->
WITH RECURSIVE
c_with_level AS (

    SELECT *, 0 as lvl
    FROM   customer_area_node
    WHERE  parent_id IS NULL

    UNION ALL

    SELECT child.*, parent.lvl + 1
    FROM   customer_area_node child
    JOIN   c_with_level parent ON parent.id = child.parent_id
),
maxlvl AS (
  SELECT max(lvl) maxlvl FROM c_with_level
),
c_tree AS (
    SELECT c_with_level.*, jsonb '[]' children
    FROM   c_with_level, maxlvl
    WHERE  lvl = maxlvl

    UNION 
    (
        SELECT (branch_parent).*, jsonb_agg(branch_child)
        FROM (
            SELECT branch_parent, branch_child
            FROM c_with_level branch_parent
            JOIN c_tree branch_child ON branch_child.parent_id = branch_parent.id
        ) branch
        GROUP BY branch.branch_parent

        UNION

        SELECT c.*, jsonb '[]' children
        FROM   c_with_level c
        WHERE  NOT EXISTS (SELECT 1 FROM c_with_level hypothetical_child WHERE hypothetical_child.parent_id = c.id)
    )
)
SELECT jsonb_pretty(row_to_json(c_tree)::jsonb)
FROM c_tree
WHERE lvl = 0;

Đã kiểm tra trên http://rextester.com/SMM38494;)



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Làm cách nào để sửa đổi các trường bên trong kiểu dữ liệu PostgreSQL JSON mới?

  2. CẬP NHẬT nguyên tử .. CHỌN trong Postgres

  3. Làm cách nào để nhập các tệp * .sql hiện có trong PostgreSQL 8.4?

  4. Tìm các hàng trong đó mảng văn bản chứa giá trị tương tự như giá trị đầu vào

  5. Ràng buộc được xác định CÓ THỂ XÁC ĐỊNH BAN ĐẦU NGAY LẬP TỨC vẫn bị XÁC ĐỊNH?