Mysql 在自引用表中查找祖先/中心的SQL
我有一个表引用了它自己,如下所示:Mysql 在自引用表中查找祖先/中心的SQL,mysql,sql,mysql5,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); DELIMITER $$ DROP FUNCTION IF EXISTS `junk`.`GetAncestry` $$ CR
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);
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 ;
样本数据:
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')
CALL find_ancestors('a1x')
会回来的
id name
3 a1
1 a
id name
3 a1
5 a1x
id name distance
3 a1 1
1 a 2
id name distance
3 a1 1
及
会回来的
id name
3 a1
1 a
id name
3 a1
5 a1x
id name distance
3 a1 1
1 a 2
id name distance
3 a1 1
如何为MySQL 5编写这些存储过程?谢谢
悬赏奖励问题:还选择返回行与源的距离,并将最大距离参数传递给过程,例如
会回来的
id name
3 a1
1 a
id name
3 a1
5 a1x
id name distance
3 a1 1
1 a 2
id name distance
3 a1 1
及
会回来的
id name
3 a1
1 a
id name
3 a1
5 a1x
id name distance
3 a1 1
1 a 2
id name distance
3 a1 1
假设我们有一个包含四个元素的表,id、item、class和parent_id。我们想要得到任何给定项的完整祖先,我们需要做的是一个定制的mysql函数,它实际上会在每个记录中循环寻找与我们的项parent_id匹配的项,一旦找到匹配项,如果匹配项有parent_id,它将再次开始循环,以此类推。每次我们的函数找到匹配项时,它都会将其存储在一个逗号分隔的字符串中,该字符串将在末尾返回,例如:1,2,3,4 我们的函数如下所示:
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);
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 ;
这段代码是RolandmySqlDBA编写的,假设我们有一个包含四个元素的表,id、item、class和parent_id。我们想要拥有任何给定项的完整祖先,我们需要做的是一个自定义mysql函数,一旦找到匹配项,它将实际循环通过每个记录寻找与我们的item parent_id匹配的项,如果匹配项具有父项id,它将再次开始循环,以此类推。每次我们的函数找到匹配项时,它都会将其存储在一个逗号分隔的字符串中,该字符串将在末尾返回,例如:1,2,3,4 我们的函数如下所示:
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);
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编写的我考虑过阅读Joe Celko在SQL for Smarties中的树和层次结构,它涵盖了这类问题。这是一个迷人的理论素材,但我一直想知道sql树,人们在实践中实际使用它们的目的是什么?在我的例子中,a是欧洲,b是亚洲,a1是奥地利,等等……啊。谢谢说读这本书作为我的答案是不够的,所以我不会把它作为答案。但上面塞尔科的书几乎就是圣经。关于它的另一种解释,请参见上面的例子,它似乎是在处理二叉树,或者至少链接的例子是这样的。而且,由于手头没有这本书,我很想给n元示例代码打分。虽然答案中给出的示例是一个二叉树,但我不认为该技术中有任何东西将其限制为二叉树。请注意,修改后的预排序树遍历技术几乎要求您的数据是固定的——对于大型动态树,您的数据库将通过不断地对树进行重新排序来进行处理。不过,通过存储过程的迭代解决方案可以让您保持结构不变。我曾考虑阅读Joe Celko在SQL for Smarties中的树和层次结构,其中涵盖了此类问题。这是一个迷人的理论素材,但我一直想知道sql树,人们在实践中实际使用它们的目的是什么?在我的例子中,a是欧洲,b是亚洲,a1是奥地利,等等……啊。谢谢说读这本书作为我的答案是不够的,所以我不会把它作为答案。但上面塞尔科的书几乎就是圣经。关于它的另一种解释,请参见上面的例子,它似乎是在处理二叉树,或者至少链接的例子是这样的。而且,由于手头没有这本书,我很想给n元示例代码打分。虽然答案中给出的示例是一个二叉树,但我不认为该技术中有任何东西将其限制为二叉树。请注意,修改后的预排序树遍历技术几乎要求您的数据是固定的——对于大型动态树,您的数据库将通过不断地对树进行重新排序来进行处理。通过存储过程的迭代解决方案将允许您保持结构不变。