Якщо ви хочете мати можливість мати SELECT без проблем батьківського ідентифікатора, який повинен бути нижчим за дочірній ідентифікатор, можна використовувати функцію. Він також підтримує декілька дочірніх систем (як це повинно робити дерево), і дерево може мати кілька головок. Це також гарантує розрив, якщо в даних існує цикл.
Я хотів використовувати динамічний SQL, щоб мати можливість передавати імена таблиць / стовпців, але функції в MySQL цього не підтримують.
DELIMITER $$
CREATE FUNCTION `isSubElement`(pParentId INT, pId INT) RETURNS int(11)
DETERMINISTIC
READS SQL DATA
BEGIN
DECLARE isChild,curId,curParent,lastParent int;
SET isChild = 0;
SET curId = pId;
SET curParent = -1;
SET lastParent = -2;
WHILE lastParent <> curParent AND curParent <> 0 AND curId <> -1 AND curParent <> pId AND isChild = 0 DO
SET lastParent = curParent;
SELECT ParentId from `test` where id=curId limit 1 into curParent;
IF curParent = pParentId THEN
SET isChild = 1;
END IF;
SET curId = curParent;
END WHILE;
RETURN isChild;
END$$
Тут таблицю test
потрібно змінити до справжньої назви таблиці, а стовпці (ParentId, Id), можливо, доведеться відкоригувати для ваших справжніх імен.
Використання:
SET @wantedSubTreeId = 3;
SELECT * FROM test WHERE isSubElement(@wantedSubTreeId,id) = 1 OR ID = @wantedSubTreeId;
Результат:
3 7 k
5 3 d
9 3 f
1 5 a
SQL для створення тесту:
CREATE TABLE IF NOT EXISTS `test` (
`Id` int(11) NOT NULL,
`ParentId` int(11) DEFAULT NULL,
`Name` varchar(300) NOT NULL,
PRIMARY KEY (`Id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
insert into test (id, parentid, name) values(3,7,'k');
insert into test (id, parentid, name) values(5,3,'d');
insert into test (id, parentid, name) values(9,3,'f');
insert into test (id, parentid, name) values(1,5,'a');
insert into test (id, parentid, name) values(6,2,'o');
insert into test (id, parentid, name) values(2,8,'c');
EDIT: Ось скрипка, щоб перевірити це самостійно. Це змусило мене змінити роздільник, використовуючи заздалегідь визначений, але це працює.