Получилась следующая таблица:
col1 | col2 | col3
-----+------+-------
1 | a | 5
5 | d | 3
3 | k | 7
6 | o | 2
2 | 0 | 8
Если пользователь ищет «1», программа будет смотреть на то, col1
что имеет «1», затем получит значение col3
«5», затем программа продолжит поиск «5» в col1
и получит «3». в col3
и так далее. Итак, он распечатает:
1 | a | 5
5 | d | 3
3 | k | 7
Если пользователь ищет «6», он распечатает:
6 | o | 2
2 | 0 | 8
Как построить SELECT
запрос для этого?
Ответы:
редактировать
Решение, упомянутое @leftclickben, также эффективно. Мы также можем использовать для этого хранимую процедуру.
CREATE PROCEDURE get_tree(IN id int) BEGIN DECLARE child_id int; DECLARE prev_id int; SET prev_id = id; SET child_id=0; SELECT col3 into child_id FROM table1 WHERE col1=id ; create TEMPORARY table IF NOT EXISTS temp_table as (select * from table1 where 1=0); truncate table temp_table; WHILE child_id <> 0 DO insert into temp_table select * from table1 WHERE col1=prev_id; SET prev_id = child_id; SET child_id=0; SELECT col3 into child_id FROM TABLE1 WHERE col1=prev_id; END WHILE; select * from temp_table; END //
Мы используем временную таблицу для хранения результатов вывода, и поскольку временные таблицы основаны на сеансах, у нас не будет проблем с неверными данными вывода.
SQL FIDDLE Demo
Попробуйте этот запрос:SELECT col1, col2, @pv := col3 as 'col3' FROM table1 JOIN (SELECT @pv := 1) tmp WHERE col1 = @pv
SQL FIDDLE Demo
:| COL1 | COL2 | COL3 | +------+------+------+ | 1 | a | 5 | | 5 | d | 3 | | 3 | k | 7 |
источник
col3
типа, поэтому, если есть несколько записей, это не сработает.Принятый ответ @Meherzad работает, только если данные находятся в определенном порядке. Бывает работать с данными из вопроса OP. В моем случае мне пришлось изменить его для работы с моими данными.
Запись Это работает только тогда, когда каждая запись «id» (col1 в вопросе) имеет значение БОЛЬШЕ, чем «родительский id» этой записи (col3 в вопросе). Это часто бывает, потому что обычно сначала нужно создать родительский элемент. Однако, если ваше приложение допускает изменения в иерархии, где элемент может быть повторно создан в другом месте, вы не можете полагаться на это.
Это мой запрос на случай, если он кому-то поможет; обратите внимание, что это не работает с данным вопросом, потому что данные не соответствуют требуемой структуре, описанной выше.
select t.col1, t.col2, @pv := t.col3 col3 from (select * from table1 order by col1 desc) t join (select @pv := 1) tmp where t.col1 = @pv
Разница в том, что
table1
он упорядочиваетсяcol1
так, что родитель будет после него (поскольку значение родительскогоcol1
элемента ниже, чем значение дочернего элемента).источник
Ответ leftclickben сработал для меня, но мне нужен был путь от заданного узла вверх по дереву к корню, и они, казалось, шли другим путем, вниз по дереву. Итак, мне пришлось перевернуть некоторые поля и переименовать для ясности, и это работает для меня, на случай, если это то, чего хочет кто-то еще ...
item | parent ------------- 1 | null 2 | 1 3 | 1 4 | 2 5 | 4 6 | 3
и
select t.item_id as item, @pv:=t.parent as parent from (select * from item_tree order by item_id desc) t join (select @pv:=6)tmp where t.item_id=@pv;
дает:
item | parent ------------- 6 | 3 3 | 1 1 | null
источник
1 3 6
я используюarray_reverse()
в php ..... любое решение sql для этого?Хранимая процедура - лучший способ сделать это. Потому что решение Мехерзада будет работать, только если данные будут следовать в том же порядке.
Если у нас есть такая структура таблицы
col1 | col2 | col3 -----+------+------ 3 | k | 7 5 | d | 3 1 | a | 5 6 | o | 2 2 | 0 | 8
Это не сработает.
SQL Fiddle Demo
Вот пример кода процедуры для достижения того же.
delimiter // CREATE PROCEDURE chainReaction ( in inputNo int ) BEGIN declare final_id int default NULL; SELECT col3 INTO final_id FROM table1 WHERE col1 = inputNo; IF( final_id is not null) THEN INSERT INTO results(SELECT col1, col2, col3 FROM table1 WHERE col1 = inputNo); CALL chainReaction(final_id); end if; END// delimiter ; call chainReaction(1); SELECT * FROM results; DROP TABLE if exists results;
источник
Если вы хотите иметь возможность иметь 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;
Результат:
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: вот скрипка, чтобы проверить это самостоятельно. Это заставило меня изменить разделитель на предопределенный, но он работает.
источник
Строительство Мастера DJon
Вот упрощенная функция, которая предоставляет дополнительную полезность для возврата глубины (в случае, если вы хотите использовать логику для включения родительской задачи или поиска на определенной глубине)
DELIMITER $$ FUNCTION `childDepth`(pParentId INT, pId INT) RETURNS int(11) READS SQL DATA DETERMINISTIC BEGIN DECLARE depth,curId int; SET depth = 0; SET curId = pId; WHILE curId IS not null AND curId <> pParentId DO SELECT ParentId from test where id=curId limit 1 into curId; SET depth = depth + 1; END WHILE; IF curId IS NULL THEN set depth = -1; END IF; RETURN depth; END$$
Применение:
select * from test where childDepth(1, id) <> -1;
источник