19

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 を再帰的に取得しようとしています。それを達成する方法はありますか?

4

5 に答える 5

17

これを行うには、隣接リストとネストされたリストの 2 つの基本的な方法があります。MySQL での階層データの管理 をご覧ください。

あなたが持っているのは隣接リストです。いいえ、単一の SQL ステートメントですべての子孫を再帰的に取得する方法はありません。可能であれば、それらすべてを取得して、コードですべてマップしてください。

入れ子になったセットはあなたが望むことを行うことができますが、レコードを挿入するコストが高く、エラーが発生しやすいため、私はそれを避ける傾向があります.

于 2009-06-13T11:13:49.873 に答える
13

これは、単純な単一クエリの 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
))
于 2016-10-17T11:54:08.953 に答える
1

それがあなたのオプションであれば、おそらくストアドプロシージャでそれを行うことができます。

そうしないと、単一の sql-statement では実行できません。

理想的には、プログラムからツリーをたどるために再帰呼び出しを行う必要があります

于 2009-06-13T12:07:11.150 に答える
1

以下のようなテーブルを作成します

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 
于 2016-09-20T06:42:12.540 に答える
-2

あなたの質問は少し不正確なようです。なぜそれらを持ちたいのですか? また、それらを「ツリーに」持つとはどういう意味ですか?

あなたが持っているテーブルは、IS (表現するリレーショナルな方法) です。

ペア (ID 4 、ParentID 0) を保持する行を含む「テーブル内」でそれらを使用する場合は、エンジンがサポートしている場合、SQL エンジンのバージョンの再帰 SQL でこれを行う必要があります。

特に MySQL については知りませんが、私の理解では、彼らはかつて Oracle と同じ構文、つまり CONNECT BY を使用して再帰 SQL を実装することを計画していたということです。

「再帰クエリ」や「CONNECT BY」などのキーワードについてマニュアルの目次を調べれば、答えが見つかるはずです。

(よりすぐに使用できる回答を提供できなくて申し訳ありません。)

于 2009-06-13T18:19:50.037 に答える