SQL在自引用表中查找祖先/后代

时间:2012-02-15 14:14:37

标签: mysql sql mysql5

我有一个引用自己的表,如下所示:

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 个答案:

答案 0 :(得分:1)

假设我们有一个包含四个元素的表,id,item,class和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撰写