ユーザー/グループシステムを拡張して、他のグループメンバーで構成される動的グループを許可しています。 3つのテーブルusers
、groups
、およびrelationships
があります。
簡単にするために、usersは1つのフィールドuser_id
のみを含み、groupsにはgroup_id
のみが含まれます。 relationships
は、user_id
、group_id
、related_group_id
の3つのフィールドを使用して、両方のユーザーをグループ化しますおよびグループからグループの関係。
動的に入力されるグループ階層は次のようになります。
ユーザーA, B, C
はグループ1
に属し、ユーザーD, E, F
はグループ2に属します。これらはすべて関係で表されますテーブルを(user_id
、group_id
)として:
A,1
B,1
C,1
D,2
E,2
F,2
動的グループ3
には、2つのgroup to group関係レコード(group_id
、related_group_id
)があります。
3,1
3,2
私の問題をよりよく説明するために、動的グループ4
を追加して、グループ3
を含めます。
4,3
MySQL CURSOR
について私が学んだことをつなぎ合わせて、fetch_inheritance_groups
と呼ばれる次のストアドプロシージャを作成しました。
DROP PROCEDURE IF EXISTS `fetch_inheritance_groups`;
CREATE PROCEDURE `fetch_inheritance_groups`(IN parent_id INT)
READS SQL DATA
BEGIN
DECLARE inherit_id char(32);
DECLARE eol BOOLEAN;
DECLARE inherit_cur CURSOR FOR SELECT r.Related_Group_ID FROM usr_relationships r WHERE r.Group_ID = parent_id AND r.Related_Group_ID IS NOT NULL;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET eol = TRUE;
OPEN inherit_cur;
inherited: LOOP
FETCH inherit_cur INTO inherit_id;
IF eol
THEN
CLOSE inherit_cur;
LEAVE inherited;
ELSE
CALL fetch_inheritance_groups(inherit_id);
END IF;
SELECT inherit_id;
END LOOP inherited;
END;
...これは...と呼ばれます.
CALL fetch_inheritance_groups(4);
...期待される結果を返します
3
2
1
ここで私の問題が始まります。それらは単一の結果セットの3つの行ではなく、3つの別々の結果セットとして返されます。次に、結果は次のようなクエリ内で使用するためのものです。
SELECT r.uer_id FROM relationships r WHERE r.group_id = 4 OR r.group_id IN (CALL fetch_inheritance_groups(4));
だから私が誰かが答えることを望んでいる3つの質問は:
1。ここでCURSOR
を使用する必要がありますか、それとも同じ再帰的な結果が得られる代替手段はありますか?
2。副選択と同じように使用できるように、結果を単一の結果セットに戻すにはどうすればよいですか
3。 CALL
の結果を使用する適切な方法は何ですか?上記のサンプルSELECTステートメントを機能させるために、少なくとも試してみたのですができないのですか?これは、CALL
をインラインで使用できないためだと思いますが、よくわかりません。
UPDATE:ここの関連する質問: 一時的なMEMORYテーブルは、ドロップしない場合、どれくらい持続しますか(MySQL) =上記で使用したストアドプロシージャに一連の更新を投稿しましたが、これはまだ再帰的ですが、IDのリストを変数として提供し、FIND_IN_SET()と互換性のある形式で提供して、必要なものを正確に提供します。
だから私が誰かが答えることを望んでいる3つの質問は:
1.ここでカーソルを使用する必要がありますか、それとも同じ再帰的な結果が得られる代替手段はありますか?
いいえ、できません。 CURSORは何度も開かれ続けています。頭上を考えると私はうんざりします。個人的に、私はカーソルから離れています。
2.副選択と同じ方法で使用できるように、結果を単一の結果セットに戻すにはどうすればよいですか?
3. CALLの結果を使用する適切な方法は何ですか?上記のサンプルSELECTステートメントを機能させるために、少なくとも試してみたのですが、できません。これは、CALLをインラインで使用できないためだと思いますが、よくわかりません。
私は、大学時代にデータ構造について学んだときに私が学んだことを提案することで、あなたを救済したいと思います。キューを使用してツリートラバーサルを実行する必要があります。これにより、ルートから開始して、ツリーのすべての子孫を表すことができます。
アルゴリズムはこのようになります
これにより、プログラムによる再帰を使用せずに再帰構造をトラバースできます。この時点で、あなたはおそらく尋ねています:再帰せずにツリー構造をトラバースするにはどうすればよいですか?
ノードのあるテーブルとテーブル内のその親をトラバースする単一のCALLでループを使用できる3つのストアドプロシージャをスクリプト化する方法について投稿しました。
投稿は 階層フィールドの最高レベルを検索:CTEありvsなし (2011年10月24日)。これには、次のテーブル構造をたどる、すでに記述されているストアドプロシージャが含まれています。
+------------+--------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+------------+--------------+------+-----+---------+----------------+
| id | int(11) | NO | PRI | NULL | auto_increment |
| parent_id | int(11) | YES | | NULL | |
| name | varchar(255) | YES | | NULL | |
| notes | text | YES | | NULL | |
+------------+--------------+------+-----+---------+----------------+
コードを注意深く読み、原則を適用してください。
試してみる !!!