SQL-поиск предков / потомков в самореферентной таблице - PullRequest
1 голос
/ 15 февраля 2012

У меня есть таблица, которая ссылается на себя, например:

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 Ответ

1 голос
/ 18 апреля 2013

Допустим, у нас есть таблица с четырьмя элементами: 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

...