邻接表到嵌套集转换

时间:2014-06-20 20:01:16

标签: mysql nested-sets adjacency-list

我需要将邻接列表转换为MySql中的嵌套集。我在互联网上只找到一个资源,使用mysql(http://data.bangtech.com/sql/nested_set_treeview.htm)将邻接列表转换为嵌套集。代码也在同一个网页上。

CREATE TABLE test.Tree
(emp CHAR(10) NOT NULL,
boss CHAR(10));

CREATE TABLE test.Personnel(
emp CHAR(20) PRIMARY KEY,
boss CHAR(20) REFERENCES Personnel(emp), 
salary DECIMAL(6,2) NOT NULL
);

INSERT INTO test.Personnel VALUES ('jerry', 'NULL',1000.00);
INSERT INTO test.Personnel VALUES ('Bert', 'jerry',900.00);
INSERT INTO test.Personnel VALUES ('chuck', 'jerry',900.00);
INSERT INTO test.Personnel VALUES ('donna', 'chuck',800.00);
INSERT INTO test.Personnel VALUES ('eddie', 'chuck',700.00);
INSERT INTO test.Personnel VALUES ('fred', 'chuck',600.00);


INSERT INTO test.Tree
SELECT emp, boss FROM test.Personnel;

我从Personnel表中创建Tree表。树表具有老板 - 员工层次结构。这是一个邻接列表。为了将它转换为嵌套集,我应用了这段代码。

BEGIN ATOMIC
DECLARE counter integer;
DECLARE max_counter integer;
DECLARE current_top integer;


SET counter = 2;
SET max_counter = 2 * (SELECT COUNT(*) FROM test.Tree);
SET current_top = 1;

INSERT INTO test.Stack
SELECT 1, emp, 1, NULL
FROM test.Tree
WHERE boss IS NULL;

DELETE FROM test.Tree
 WHERE boss IS NULL;

WHILE counter <=(max_counter - 2)
 LOOP IF EXISTS (SELECT * FROM test.Stack AS S1, test.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 test.Stack
  SELECT (current_top + 1), MIN(T1.emp), counter, NULL
  FROM test.Stack AS S1, test.Tree AS T1
   WHERE S1.emp = T1.boss
   AND S1.stack_top = current_top;

   DELETE FROM test.Tree
   WHERE emp = (SELECT emp
   FROM test.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 test.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;

MySQL工作台显示了一些我无法删除的语法错误。

我只熟悉mysql的非常基本的操作,所以无法自己调试代码。如何删除所有这些错误? Plz帮助。 我发现执行上述操作的第二个来源是http://www.sqlservercentral.com/articles/Hierarchy/94040/,但代码是在T Sql中,我没有足够的技能将其转换为MySQL。

2 个答案:

答案 0 :(得分:0)

你应该在行

中放置NULL而不是'NULL'
  

INSERT INTO test.Personnel VALUES('jerry','NULL',1000.00);

正确版本:

  

INSERT INTO test.Personnel VALUES('jerry',NULL,1000.00);

答案 1 :(得分:0)

使用Bash:

Bash转换:

# SQL command to fetch necessary fields, output it to text archive "tree"
SELECT id, parent_id, name FROM projects;

# Make a list "id|parentid|name" and sort by name
cat tree |
  cut -d "|" -f 2-4 |
  sed 's/^ *//;s/ *| */|/g' |
  sort -t "|" -k 3,3 > list

# Creates the parenthood chain on second field
while IFS="|" read i p o
do
  l=$p
  while [[ "$p" != "NULL" ]]
  do
    p=$(grep -w "^$p" list | cut -d "|" -f 2)
    l="$l,$p"
  done
  echo "$i|$l|$o"
done < list > listpar

# Creates left and right on 4th and 5th fields for interaction 0
let left=0
while IFS="|" read i l o
do
  let dif=$(grep "\b$i,NULL|" listpar | wc -l)*2+1
  let right=++left+dif
  echo "$i|$l|$o|$left|$right"
  let left=right
done <<< "$(grep "|NULL|" listpar)" > i0

# The same for following interactions
n=0
while [ -s i$n ]
do
  while IFS="|" read i l nil left nil
  do
    grep "|$i,$l|" listpar |
    while IFS="|" read i l o
    do
      let dif=$(grep "\b$i,$l|" listpar | wc -l)*2+1
      let right=++left+dif
      echo "$i|$l|$o|$left|$right"
      let left=right
    done
  done < i$n > i$((++n))
done

# Show concatenated
cat i*|sort -t"|" -k 4n

# SQL commands
while IFS="|" read id nil nil left right
do
  echo "UPDATE projects SET lft=$left, rgt=$right WHERE id=$id;"
done <<< "$(cat i*)"