Martin
2004-07-18 09:46:14 UTC
Hi,
I am designing a tree structure in my database and I found nearly the
perfect solution to my problem at
http://www.intelligententerprise.com/001020/celko1_2.jhtml
The only problem is I can't get it to work (at least not perfectly) in sql
server. I am basically trying to produce a nested set from an adjacency
list.
The original article was displayed in another implementaion of sql (P/SQL i
think.)
anyway, I took it and converted it to T-sql however it appears to not work
correctly.
If anybody has seen this problem before or could point out where I am going
wrong then I would very much appreciate it.
I have provided the T-SQL that I have at present below
===================================================================
use master
go
DROP DATABASE HIERACHY
GO
CREATE DATABASE HIERACHY
go
use HIERACHY
go
CREATE TABLE Tree
(emp CHAR(10) NOT NULL,
boss CHAR(10));
go
CREATE TABLE Stack
(stack_top INTEGER NOT NULL,
emp CHAR(10) NOT NULL,
lft INTEGER,
rgt INTEGER);
go
====================================
--May have to run below code multiple times
delete from Tree
delete from stack
INSERT INTO Tree SELECT 'Albert',NULL--,1000
INSERT INTO Tree SELECT 'Bert','Albert'--,900
INSERT INTO Tree SELECT 'Chuck','Albert'--,900
INSERT INTO Tree SELECT 'Donna','Chuck'--,800
INSERT INTO Tree SELECT 'Eddie','Chuck'--,700
INSERT INTO Tree SELECT 'Fred','Chuck'--,600
--BEGIN ATOMIC
--delete from stack
--select * from stack
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)
BEGIN
IF EXISTS (SELECT *
FROM Stack AS S1, Tree AS T1
WHERE S1.emp = T1.boss
AND S1.stack_top = @current_top)
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
END
--Finally output the resultset
select * from stack
I am designing a tree structure in my database and I found nearly the
perfect solution to my problem at
http://www.intelligententerprise.com/001020/celko1_2.jhtml
The only problem is I can't get it to work (at least not perfectly) in sql
server. I am basically trying to produce a nested set from an adjacency
list.
The original article was displayed in another implementaion of sql (P/SQL i
think.)
anyway, I took it and converted it to T-sql however it appears to not work
correctly.
If anybody has seen this problem before or could point out where I am going
wrong then I would very much appreciate it.
I have provided the T-SQL that I have at present below
===================================================================
use master
go
DROP DATABASE HIERACHY
GO
CREATE DATABASE HIERACHY
go
use HIERACHY
go
CREATE TABLE Tree
(emp CHAR(10) NOT NULL,
boss CHAR(10));
go
CREATE TABLE Stack
(stack_top INTEGER NOT NULL,
emp CHAR(10) NOT NULL,
lft INTEGER,
rgt INTEGER);
go
====================================
--May have to run below code multiple times
delete from Tree
delete from stack
INSERT INTO Tree SELECT 'Albert',NULL--,1000
INSERT INTO Tree SELECT 'Bert','Albert'--,900
INSERT INTO Tree SELECT 'Chuck','Albert'--,900
INSERT INTO Tree SELECT 'Donna','Chuck'--,800
INSERT INTO Tree SELECT 'Eddie','Chuck'--,700
INSERT INTO Tree SELECT 'Fred','Chuck'--,600
--BEGIN ATOMIC
--delete from stack
--select * from stack
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)
BEGIN
IF EXISTS (SELECT *
FROM Stack AS S1, Tree AS T1
WHERE S1.emp = T1.boss
AND S1.stack_top = @current_top)
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
END
--Finally output the resultset
select * from stack