2012-02-15 44 views
1

我有引用本身,像这样的表:SQL寻找祖先/ decendants在自引用表

CREATE TABLE Foo (
id INT NOT NULL AUTO_INCREMENT PRIMARY KEY, 
parent INT NULL, 
name VARCHAR (30) NOT NULL, 
FOREIGN KEY (parent) REFERENCES Foo(id) ON DELETE CASCADE); 

的样本数据:

id parent name 
1 NULL a 
2 NULL b 
3 1  a1 
4 1  a2 
5 3  a1x 
6 3  a2x 

我想写的查询将列出给定行的祖先和行人,例如

CALL find_ancestors('a1x') 

将返回

id name 
3 a1 
1 a 

CALL find_descendants('a') 

将返回

id name 
3 a1 
5 a1x 

怎么能写我的MySQL 5这些存储过程?对于奖金感谢


奖金的问题:也选择从源返回的行的距离和最大距离参数传递给过程,例如

CALL find_ancestors('a1x') 

将返回

id name distance 
3 a1 1 
1 a 2 

CALL find_ancestors_bounded('a1x',1) 

将返回

id name distance 
3 a1 1 
+1

撰写我认为读书“乔·塞科的树木和层次结构在SQL为Smarties一”,讲述了这些类型的问题。这是令人着迷的理论性的东西,但我一直想知道sql树,人们在实践中实际使用它们的是什么? – 2012-02-15 14:54:18

+0

在我的情况下,a是欧洲,b是亚洲,a1是奥地利等等。 – spraff 2012-02-15 15:24:39

+0

啊。谢谢。将“读这本书”作为我的回答,感觉不足,所以我没有把它作为答案。但Celko的上面的书几乎是圣经。有关它的另一种解释,请参见[StackOverflow:是否有可能在单个查询中查询MySQL中的树形结构表,以便查看任何深度?](http://stackoverflow.com/questions/169817/is-it-possible-查询树结构表中的mysql-in-a-one-query-to-an) – 2012-02-15 15:58:57

回答

1

假设我们有一个表有四个要素,编号,项目,类别和PARENT_ID 。我们希望拥有任何给定项目的完整祖先,我们需要做的是自定义mysql函数,该函数实际上会遍历每个查找匹配项目parent_id的记录,一旦找到匹配项,如果匹配的项目具有匹配parent_id,它将再次开始循环,等等。我们的每一次函数找到一个匹配后,将其存储在将在年底返回的逗号分隔字符串(如:1,2,3,4)

我们的功能会是这个样子:

DELIMITER $$ 
DROP FUNCTION IF EXISTS `junk`.`GetAncestry` $$ 
CREATE FUNCTION `junk`.`GetAncestry` (GivenID INT) RETURNS VARCHAR(1024) 
DETERMINISTIC 
BEGIN 
    DECLARE rv VARCHAR(1024); 
    DECLARE cm CHAR(1); 
    DECLARE ch INT; 

    SET rv = ''; 
    SET cm = ''; 
    SET ch = GivenID; 
    WHILE ch > 0 DO 
     SELECT IFNULL(parent_id,-1) INTO ch FROM 
     (SELECT parent_id FROM pctable WHERE id = ch) A; 
     IF ch > 0 THEN 
      SET rv = CONCAT(rv,cm,ch); 
      SET cm = ','; 
     END IF; 
    END WHILE; 
    RETURN rv; 
END $$ 
DELIMITER ; 

此代码是由RolandoMySQLDBA