Bạn không thể thực hiện đệ quy trong SQL mà không có thủ tục được lưu trữ. Cách để giải quyết điều này là sử dụng Nested Sets, về cơ bản, họ mô hình hóa một cây trong SQL như một tập hợp.
Lưu ý rằng điều này sẽ yêu cầu thay đổi đối với mô hình dữ liệu hiện tại hoặc có thể tìm ra cách tạo chế độ xem trên mô hình ban đầu.
PostgreSQL dụ (sử dụng rất ít các phần mở rộng postgresql, chỉ SERIAL và ON COMMIT DROP, nhất RDBMSes sẽ có chức năng tương tự):
Setup:
CREATE TABLE objects(
id SERIAL PRIMARY KEY,
name TEXT,
lft INT,
rgt INT
);
INSERT INTO objects(name, lft, rgt) VALUES('The root of the tree', 1, 2);
Thêm một đứa trẻ:
START TRANSACTION;
-- postgresql doesn't support variables so we create a temporary table that
-- gets deleted after the transaction has finished.
CREATE TEMP TABLE left_tmp(
lft INT
) ON COMMIT DROP; -- not standard sql
-- store the left of the parent for later use
INSERT INTO left_tmp (lft) VALUES((SELECT lft FROM objects WHERE name = 'The parent of the newly inserted node'));
-- move all the children already in the set to the right
-- to make room for the new child
UPDATE objects SET rgt = rgt + 2 WHERE rgt > (SELECT lft FROM left_tmp LIMIT 1);
UPDATE objects SET lft = lft + 2 WHERE lft > (SELECT lft FROM left_tmp LIMIT 1);
-- insert the new child
INSERT INTO objects(name, lft, rgt) VALUES(
'The name of the newly inserted node',
(SELECT lft + 1 FROM left_tmp LIMIT 1),
(SELECT lft + 2 FROM left_tmp LIMIT 1)
);
COMMIT;
Hiển thị đường nhỏ từ dưới lên trên:
SELECT
parent.id, parent.lft
FROM
objects AS current_node
INNER JOIN
objects AS parent
ON
current_node.lft BETWEEN parent.lft AND parent.rgt
WHERE
current_node.name = 'The name of the deepest child'
ORDER BY
parent.lft;
Hiển thị toàn bộ cây:
SELECT
REPEAT(' ', CAST((COUNT(parent.id) - 1) AS INT)) || '- ' || current_node.name AS indented_name
FROM
objects current_node
INNER JOIN
objects parent
ON
current_node.lft BETWEEN parent.lft AND parent.rgt
GROUP BY
current_node.name,
current_node.lft
ORDER BY
current_node.lft;
Chọn tất cả mọi thứ xuống từ một yếu tố nào đó của cây:
SELECT
current_node.name AS node_name
FROM
objects current_node
INNER JOIN
objects parent
ON
current_node.lft BETWEEN parent.lft AND parent.rgt
AND
parent.name = 'child'
GROUP BY
current_node.name,
current_node.lft
ORDER BY
current_node.lft;
Trong gì RDBMS giải pháp nên chạy? Nếu đó là Oracle, sau đó tìm hiểu về CONNECT BY PRIOR – Salamander2007
xin lỗi, quên đề cập đến, trong MSSQL 2005 –