Si desea poder tener un SELECT sin problemas de que la identificación principal tenga que ser menor que la identificación secundaria, se podría usar una función. También admite varios niños (como debería hacer un árbol) y el árbol puede tener varias cabezas. También asegura que se rompa si existe un bucle en los datos.
Quería usar SQL dinámico para poder pasar los nombres de tablas / columnas, pero las funciones en MySQL no admiten esto.
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$$
Aquí, la tabla test
debe modificarse al nombre real de la tabla y es posible que las columnas (ParentId, Id) tengan que ajustarse a sus nombres reales.
Uso:
SET @wantedSubTreeId = 3;
SELECT * FROM test WHERE isSubElement(@wantedSubTreeId,id) = 1 OR ID = @wantedSubTreeId;
Resultado:
3 7 k
5 3 d
9 3 f
1 5 a
SQL para la creación de pruebas:
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');
EDITAR: Aquí hay un violín para probarlo usted mismo. Me obligó a cambiar el delimitador usando el predefinido, pero funciona.