2009-06-08 14 views
2

ツリーの子ノードを返す効率的なクエリを探しています。 データ構造は次のとおりです。ツリーのすべての子ノードを取得する効率的なクエリ(mysql)

`ct_cid` int(10) unsigned NOT NULL default '0', // the data 
    `ct_level` int(10) unsigned NOT NULL default '0', // the level (0 = topmost) 
    `ct_parent` int(10) unsigned NOT NULL default '0', // parent ct_cid 

私はツリーが壊れたり、2つのノードが親としてお互いを指していても無限ループは存在しないだろうことを確認する必要があります。

答えて

0

私はSQLクエリを使用して、必要なデータセットを作成するためにすべてのレコードをループします。

SELECT 
     * 
    FROM 
     category 
    ORDER BY 
     name ASC 

その後、

これはあなたを助けるもの!

+0

上記の例はPHPです。 $ categoryData ['parents'] [$ category_id]を使用して、目的のツリーを取り出すことができます。 – TigerTiger

+1

非常に効率的ではないようです。 – Nir

4

MySQLで効率的にそれを行う方法についての私のブログで、このエントリを参照してください:

次の2つの関数を作成する必要があります:

CREATE FUNCTION hierarchy_connect_by_parent_eq_prior_id_with_level_and_loop(value INT, maxlevel INT) RETURNS INT 
NOT DETERMINISTIC 
READS SQL DATA 
BEGIN 
     DECLARE _id INT; 
     DECLARE _parent INT; 
     DECLARE _next INT; 
     DECLARE _i INT; 
     DECLARE CONTINUE HANDLER FOR NOT FOUND SET @id = NULL; 

     SET _parent = @id; 
     SET _id = -1; 
     SET _i = 0; 

     IF @id IS NULL THEN 
       RETURN NULL; 
     END IF; 

     LOOP 
       SELECT MIN(id) 
       INTO @id 
       FROM t_hierarchy 
       WHERE parent = _parent 
         AND id > _id 
         -- Checking for @start_with in descendants 
         AND id <> @start_with 
         AND COALESCE(@level < maxlevel, TRUE); 
       IF @id IS NOT NULL OR _parent = @start_with THEN 
         SET @level = @level + 1; 
         RETURN @id; 
       END IF; 
       SET @level := @level - 1; 
       SELECT id, parent 
       INTO _id, _parent 
       FROM t_hierarchy 
       WHERE id = _parent; 
       SET _i = _i + 1; 
     END LOOP; 
     RETURN NULL; 
END 

CREATE FUNCTION hierarchy_connect_by_iscycle(node INT) RETURNS INT 
NOT DETERMINISTIC 
READS SQL DATA 
BEGIN 
     DECLARE _id INT; 
     DECLARE _loop INT; 
     DECLARE _node INT; 
     DECLARE EXIT HANDLER FOR NOT FOUND RETURN 0; 
     SET _id = COALESCE(node, @id); 
     SET _loop = 0; 
     SET _node = 0; 
     LOOP 
       SELECT parent 
       INTO _id 
       FROM t_hierarchy 
       WHERE id = _id; 
       IF _id = @start_with THEN 
         SET _loop := _loop + 1; 
       END IF; 
       IF _id = COALESCE(node, @id) THEN 
         SET _node = _node + 1; 
       END IF; 
       IF _loop >= 2 THEN 
         RETURN _node; 
       END IF; 
     END LOOP; 
END 
CONNECT BYCONNECT_BY_ISCYCLEをエミュレートし、クエリでそれらを使用することになり

SELECT CONCAT(REPEAT(' ', lvl - 1), hi.id) AS treeitem, 
     hierarchy_sys_connect_by_path('/', hi.id) AS path, 
     parent, lvl, 
     CASE 
      WHEN lvl >= @maxlevel THEN 1 
      ELSE COALESCE(
      (
      SELECT 0 
      FROM t_hierarchy hl 
      WHERE hl.parent = ho.id 
        AND hl.id <> @start_with 
      LIMIT 1 
      ), 1) 
     END AS is_leaf, 
     hierarchy_connect_by_iscycle(hi.id) AS is_cycle 
FROM (
     SELECT hierarchy_connect_by_parent_eq_prior_id_with_level_and_loop(id, @maxlevel) AS id, 
       CAST(@level AS SIGNED) AS lvl 
     FROM (
       SELECT @start_with := 97657, 
         @id := @start_with, 
         @level := 0, 
         @maxlevel := NULL 
       ) vars, t_hierarchy 
     WHERE @id IS NOT NULL 
     ) ho 
JOIN t_hierarchy hi 
ON  hi.id = ho.id 
1

これは私の問題です。 再帰的なクエリ。

function select_child_ids($parent_id,&$ida) { 

    global $sql; 

    $items = $sql->select_column("SELECT id FROM test WHERE parent_id = ".$parent_id); 

    if ($items) { 
     foreach ($items as $id) { 
      $ida[] = $id; 
      select_child_ids($id,$ida); 
     } 
    } else { 
     return false; 
    } 
} 

メモ$ sqlは、mysqlで動作するmyクラスのサンプルです。あなたは自分で使うことができます。 実行後、配列$ idaの子要素を読み取ることができます

+0

私はOPが純粋なMySQLソリューションを望んでいたと思います。再帰的なPHP関数ではありません。しかしこれはおそらくまだいくつかの人にとっては役に立つかもしれません。 – John

関連する問題