4

私がこの例の線に沿って何かを持っていると仮定します:

CREATE TABLE NaiveTable
{
    id BIGINT NOT NULL, 
    parentId BIGINT NULL,
    name VARCHAR(20) NULL,
    CONSTRAINT hierarchy FOREIGN KEY (parentId) REFERENCES NaiveTable(id)
    PRIMARY KEY (id)
}

注意として、parentIdはNaiveTableのIDへの参照です(正確な構文を見逃した場合に備えて)。

データはこれらの線に沿ったどこかにあります

+---------+----------+----------+
|   id    | parentId |  name    | 
+---------+----------+----------+
|   1     |   null   |  node1   |
+---------+----------+----------+
|   2     |     1    |  node2   |
+---------+----------+----------+
|   3     |     1    |  node3   |
+---------+----------+----------+
|   4     |     2    |  node4   |
+---------+----------+----------+

列名に未実現のラベルがいくつか含まれています。MySQLテーブルでSQLクエリを作成する方法を探しています。この場合、すべての情報が次のようにフラット化され、階層的に並べ替えられます。

node 1, depth 0
node 2, depth 1
node 4, depth 2
node 3, depth 1

注:データベーススキーマを変更することはできません。SQLクエリしか作成できません。またWITH、MySQLがキーワードをサポートしていないため、キーワードを使用できません。そのようなクエリを作成する方法はありますか?ただし、 深さ2以上のソリューションは、十分であると見なされます。

編集:あなたが実験するのが好きなら、これがSQLフィドルです:)

4

2 に答える 2

1

データベースのスキーマが固定されていて、テーブルを追加/編集できない場合は、メモリ内にツリーを構築し(プログラミング言語で)、各ノードのメモリ内の深さを計算するだけです。だから私の答えは、1つのクエリだけでは目的の出力を生成できないということです!

ただし、データベースのスキーマを変更できる場合は、これを確認することをお勧めします。

于 2012-10-04T13:34:04.100 に答える
0

これは少し再帰的なストアドプロシージャであり、どの深さでも機能するはずです。これは私の最初のストアドプロシージャなので、改善方法を教えてください。

DROP PROCEDURE IF EXISTS tree_reader;
DELIMITER $$
CREATE PROCEDURE tree_reader(IN parent INT, IN depth INT) READS SQL DATA
BEGIN

  DECLARE id_val INT;
  DECLARE name_val VARCHAR(255);
  DECLARE _table_name VARCHAR(255);

  DECLARE no_more_rows BOOLEAN;
  DECLARE cur CURSOR FOR
      SELECT id, name
      FROM tree
      WHERE IF(parent IS NULL, parentid IS NULL, parentid = parent);

  DECLARE CONTINUE HANDLER FOR NOT FOUND SET no_more_rows = TRUE;

  -- create temporary table on outer call only --
  IF depth=0 THEN
    DROP TABLE IF EXISTS _tree;
    CREATE TEMPORARY TABLE _tree (id INT, name VARCHAR(255), depth INT);
  END IF;

  OPEN cur;

  -- loop with recursion --
  tree_loop: LOOP
    FETCH cur INTO id_val, name_val;
    IF no_more_rows THEN LEAVE tree_loop; END IF;
    INSERT INTO _tree VALUES (id_val, name_val, depth);
    CALL tree_reader(id_val, depth + 1);

  END LOOP tree_loop;

  CLOSE cur;

  -- output results on outer call only --
  IF depth=0 THEN
    SELECT * FROM _tree;
    DROP TABLE _tree;
  END IF;
END
$$
DELIMITER ;

いくつかの注意:

  • 手順を呼び出します。CALL tree_reader(NULL, 0);

  • 任意の親ノードIDを使用できますが、2番目の引数は常に0です。実際には、引数をとらずにツリー全体を提供するラッパープロシージャを追加するでしょう。

  • それが機能するためには再帰制限を設定する必要があります:(SET max_sp_recursion_depth = 6;私は任意に6を選択しました)。

于 2012-10-04T14:45:21.947 に答える