SQL 在自引用表中查找祖先/后代
Posted
技术标签:
【中文标题】SQL 在自引用表中查找祖先/后代【英文标题】:SQL finding ancestors/decendants in a self-referencing table 【发布时间】:2012-03-06 21:19:10 【问题描述】:我有一个引用自身的表,如下所示:
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
【问题讨论】:
我考虑阅读“Joe Celko 为 Smarties 编写的 SQL 中的树和层次结构”,其中涵盖了这类问题。这是很有趣的理论知识,但我一直想知道 sql 树,人们在实践中实际使用它们做什么? 在我的例子中,a 是欧洲,b 是亚洲,a1 是奥地利,等等...... 啊。谢谢。说“读这本书”作为我的答案感觉不够,所以我没有把它作为答案。但是上面的塞尔科的书几乎是圣经。其他解释见***: Is it possible to query a tree structure table in MySQL in a single query, to any depth? 上面似乎是在处理二叉树,或者至少链接的例子是这样。而且,由于手头没有这本书,我很想给 n 元示例代码加分。 虽然答案中给出的示例是二叉树,但我认为该技术中没有任何东西将其限制为二叉树。 (请注意,修改的预排序树遍历技术几乎要求您的数据是固定的——对于大型动态树,您的数据库将通过不断地重新排序树而被淹没。)存储过程的迭代解决方案将允许您保持结构不变. 【参考方案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 编写
【讨论】:
以上是关于SQL 在自引用表中查找祖先/后代的主要内容,如果未能解决你的问题,请参考以下文章