MySQL のみを使用して、ツリー内の子からすべての ID を取得したいと考えています。
次のようなテーブルがあります。
ID parent_id name
1 0 cat1
2 1 subcat1
3 2 sub-subcat1
4 2 sub-subcat2
5 0 cat2
今、cat1 (2,3,4) のすべての子 ID を再帰的に取得しようとしています。それを達成する方法はありますか?
これを行うには、隣接リストとネストされたリストの 2 つの基本的な方法があります。MySQL での階層データの管理 をご覧ください。
あなたが持っているのは隣接リストです。いいえ、単一の SQL ステートメントですべての子孫を再帰的に取得する方法はありません。可能であれば、それらすべてを取得して、コードですべてマップしてください。
入れ子になったセットはあなたが望むことを行うことができますが、レコードを挿入するコストが高く、エラーが発生しやすいため、私はそれを避ける傾向があります.
これは、単純な単一クエリの MySql ソリューションです。
SELECT GROUP_CONCAT(Level SEPARATOR ',') FROM (
SELECT @Ids := (
SELECT GROUP_CONCAT(`ID` SEPARATOR ',')
FROM `table_name`
WHERE FIND_IN_SET(`parent_id`, @Ids)
) Level
FROM `table_name`
JOIN (SELECT @Ids := <id>) temp1
) temp2
親<id>要素のID.
これは、 =で区切られIDた要素のすべての子孫の s を含む文字列を返します。複数の行が返され、各行に 1 つの子孫がある場合は、次のようなものを使用できます。ID<id>,
SELECT *
FROM `table_name`
WHERE FIND_IN_SET(`ID`, (
SELECT GROUP_CONCAT(Level SEPARATOR ',') FROM (
SELECT @Ids := (
SELECT GROUP_CONCAT(`ID` SEPARATOR ',')
FROM `table_name`
WHERE FIND_IN_SET(`parent_id`, @Ids)
) Level
FROM `table_name`
JOIN (SELECT @Ids := <id>) temp1
) temp2
))
ルート/親要素を含める
OP は、上記で回答した要素の子を要求しました。場合によっては、結果にルート/親要素を含めると便利な場合があります。これが私の提案する解決策です:
ID のコンマ区切り文字列:
SELECT GROUP_CONCAT(Level SEPARATOR ',') FROM (
SELECT <id> Level
UNION
SELECT @Ids := (
SELECT GROUP_CONCAT(`ID` SEPARATOR ',')
FROM `table_name`
WHERE FIND_IN_SET(`parent_id`, @Ids)
) Level
FROM `table_name`
JOIN (SELECT @Ids := <id>) temp1
) temp2
複数の行:
SELECT *
FROM `table_name`
WHERE `ID` = <id> OR FIND_IN_SET(`ID`, (
SELECT GROUP_CONCAT(Level SEPARATOR ',') FROM (
SELECT @Ids := (
SELECT GROUP_CONCAT(`ID` SEPARATOR ',')
FROM `table_name`
WHERE FIND_IN_SET(`parent_id`, @Ids)
) Level
FROM `table_name`
JOIN (SELECT @Ids := <id>) temp1
) temp2
))
それがあなたのオプションであれば、おそらくストアドプロシージャでそれを行うことができます。
そうしないと、単一の sql-statement では実行できません。
理想的には、プログラムからツリーをたどるために再帰呼び出しを行う必要があります
以下のようなテーブルを作成します
DROP TABLE IF EXISTS `parent_child`;
CREATE TABLE `parent_child` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(255) DEFAULT NULL,
`parent_id` int(11) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=9 DEFAULT CHARSET=latin1;
insert into `parent_child`(`id`,`name`,`parent_id`)
values (1,'cat1',0),(2,'subcat1',1),
(3,'sub-subcat1',2),(4,'sub-subcat2',2),
(5,'cat2',0);
親子要素を取得する関数を作成する
DELIMITER $$
USE `yourdatabase`$$
DROP FUNCTION IF EXISTS `GetAllNode1`$$
CREATE DEFINER=`root`@`localhost` FUNCTION `GetAllNode1`(GivenID INT) RETURNS TEXT CHARSET latin1
DETERMINISTIC
BEGIN
DECLARE rv,q,queue,queue_children TEXT;
DECLARE queue_length,front_id,pos INT;
SET rv = '';
SET queue = GivenID;
SET queue_length = 1;
WHILE queue_length > 0 DO
SET front_id = queue;
IF queue_length = 1 THEN
SET queue = '';
ELSE
SET pos = LOCATE(',',queue) + 1;
SET q = SUBSTR(queue,pos);
SET queue = q;
END IF;
SET queue_length = queue_length - 1;
SELECT IFNULL(qc,'') INTO queue_children
FROM (SELECT GROUP_CONCAT(id) AS qc
FROM `parent_child` WHERE `parent_id` = front_id) A ;
IF LENGTH(queue_children) = 0 THEN
IF LENGTH(queue) = 0 THEN
SET queue_length = 0;
END IF;
ELSE
IF LENGTH(rv) = 0 THEN
SET rv = queue_children;
ELSE
SET rv = CONCAT(rv,',',queue_children);
END IF;
IF LENGTH(queue) = 0 THEN
SET queue = queue_children;
ELSE
SET queue = CONCAT(queue,',',queue_children);
END IF;
SET queue_length = LENGTH(queue) - LENGTH(REPLACE(queue,',','')) + 1;
END IF;
END WHILE;
RETURN rv;
END$$
DELIMITER ;
欲望の出力のためのクエリを書く
SELECT GetAllNode1(id) FROM parent_child
or
SELECT GetAllNode1(id) FROM parent_child where id =1 //for specific parent's child element
あなたの質問は少し不正確なようです。なぜそれらを持ちたいのですか? また、それらを「ツリーに」持つとはどういう意味ですか?
あなたが持っているテーブルは、IS (表現するリレーショナルな方法) です。
ペア (ID 4 、ParentID 0) を保持する行を含む「テーブル内」でそれらを使用する場合は、エンジンがサポートしている場合、SQL エンジンのバージョンの再帰 SQL でこれを行う必要があります。
特に MySQL については知りませんが、私の理解では、彼らはかつて Oracle と同じ構文、つまり CONNECT BY を使用して再帰 SQL を実装することを計画していたということです。
「再帰クエリ」や「CONNECT BY」などのキーワードについてマニュアルの目次を調べれば、答えが見つかるはずです。
(よりすぐに使用できる回答を提供できなくて申し訳ありません。)