This has some predictable results that we can use for building queries. The root is always of the form (left = 1, right = 2 * (SELECT COUNT(*) FROM TreeTable)); leaf nodes always have (left + 1 = right); the BETWEEN predicate defines the subtrees; and so on. Here are some common queries that you can use to build others:
我们可以利用一些可预见的结果构建查询(表达式)。根部总是以这种形式构成(left = 1, right = 2 * (SELECT COUNT(*) FROM TreeTable));叶子节点则总是(left + 1 = right);BETWEEN表达定义了子树;等等。这里有一些常用的查询,你可以用它们来组建更多其他(查询):
1. Find an employee and all his/her supervisors, no matter how deep the tree.
查找一个雇员及他/她的所有上级,无论这颗树结构有多深。
SELECT P2.*
FROM Personnel AS P1, Personnel AS P2
WHERE P1.lft BETWEEN P2.lft AND P2.rgt
AND P1.emp = :myemployee;
2. Find the employee and all his/her subordinates. (This query has a nice symmetry with the first query.)
查找雇员及他/她所有下属。(这个查询与第一个查询形成良好的对称。)
SELECT P2.*
FROM Personnel AS P1, Personnel AS P2
WHERE P1.lft BETWEEN P2.lft AND P2.rgt
AND P2.emp = :myemployee;
3. Add a GROUP BY and aggregate functions to these basic queries and you have hierarchical reports. For example, the total salaries that each employee controls:
给这些基本查询添加GROUP BY(关键字)和总计函数这样你就有分级记录了。例如,每个雇员能支配的薪酬总数:
SELECT P2.emp, SUM(S1.salary)
FROM Personnel AS P1, Personnel AS P2,
Salaries AS S1
WHERE P1.lft BETWEEN P2.lft AND P2.rgt
AND P1.emp = S1.emp
GROUP BY P2.emp;
In the adjacency list method, this has to be done with a cursor.
在邻接列表模式里,必须依靠游标(cursor)才能这样做。
4. Find the level of each node, so you can print the tree as an indented listing.
查找每个节点的级别,这样你就能够以缩进列表形式打印这棵树了。
SELECT COUNT(P2.emp) AS indentation, P1.emp
FROM Personnel AS P1, Personnel AS P2
WHERE P1.lft BETWEEN P2.lft AND P2.rgt
GROUP BY P1.emp
ORDER BY P1.lft;
5. The nested set model has an implied ordering of siblings that the adjacency list model does not. To insert a new node as the rightmost sibling:
嵌套集合模式有一种邻接列表模式不具有的内在节点顺序。插入一个新节点以作为最右边的节点:
BEGIN
DECLARE right_most_sibling INTEGER;
SET right_most_sibling
= (SELECT rgt
FROM Personnel
WHERE emp = :your_boss);
UPDATE Personnel
SET lft = CASE WHEN lft > right_most_sibling
THEN lft + 2
ELSE lft END,
rgt = CASE WHEN rgt >= right_most_sibling
THEN rgt + 2
ELSE rgt END
WHERE rgt >= right_most_sibling;
INSERT INTO Personnel (emp, lft, rgt)
VALUES ('New Guy', right_most_sibling,
(right_most_sibling + 1))
END;
6. To convert an adjacency list model into a nested set model, use a push down stack algorithm. Assume that we have these tables:
要将邻接列表模式转换为嵌套集合模式,(需要)使用向下推进的栈式算法。假设我们有下列表:
-- Tree holds the adjacency model
--树结构控制着邻接模式
CREATE TABLE Tree
(emp CHAR(10) NOT NULL,
boss CHAR(10));
INSERT INTO Tree
SELECT emp, boss FROM Personnel;
-- Stack starts empty, will holds the nested set model
CREATE TABLE Stack
(stack_top INTEGER NOT NULL,
emp CHAR(10) NOT NULL,
lft INTEGER,
rgt INTEGER);
BEGIN ATOMIC
DECLARE counter INTEGER;
DECLARE max_counter INTEGER;
DECLARE current_top INTEGER;
SET counter = 2;
SET max_counter = 2 * (SELECT COUNT(*) FROM Tree);
SET current_top = 1;
INSERT INTO Stack
SELECT 1, emp, 1, NULL
FROM Tree
WHERE boss IS NULL;
DELETE FROM Tree
WHERE boss IS NULL;
WHILE counter <= (max_counter - 2)
LOOP IF EXISTS (SELECT *
FROM Stack AS S1, Tree AS T1
WHERE S1.emp = T1.boss
AND S1.stack_top = current_top)
THEN
BEGIN -- push when top has subordinates, set lft value
INSERT INTO Stack
SELECT (current_top + 1), MIN(T1.emp), counter, NULL
FROM Stack AS S1, Tree AS T1
WHERE S1.emp = T1.boss
AND S1.stack_top = current_top;
DELETE FROM Tree
WHERE emp = (SELECT emp
FROM Stack
WHERE stack_top = current_top + 1);
SET counter = counter + 1;
SET current_top = current_top + 1;
END
ELSE
BEGIN -- pop the stack and set rgt value
UPDATE Stack
SET rgt = counter,
stack_top = -stack_top -- pops the stack
WHERE stack_top = current_top
SET counter = counter + 1;
SET current_top = current_top - 1;
END IF;
END LOOP;
END;
Although this procedure works, you might want to use a language that has arrays in it, instead of trying to stick to pure SQL.
尽管这个存储过程很有效,你也许更乐意在这个存储过程里调用某个编程语言(譬如C或JAVA),而不是用纯SQL方式运行。
Joe Celko is an Atlanta-based independent consultant. He is the author of Instant SQL Programming (Wrox Press, 1997). You can contact him at www.celko.com or 71062.1056@compuserve.com.
Joe Celko是亚特兰大的独立顾问。他也是《 Instant SQL Programming》的作者。你可以通过www.celko.com或者 71062.1056@compuserve.com与他联系。