2011-01-18 9 views
0

注:このすべての追加情報を読む前に、実際の質問を読むには下にスキップしてください。MySQLで木からレコードを選択

私はCakePHPのACL実装に取り​​組んでいます。主に私はAuthComponenyからデカップリングしようとしているので、自分のプロジェクトにAuthsomeを使うことができます。私は実装の理論がダウンしているが、私はちょっとした障害にぶつかった。

明らかに、データベースクエリの数を最小限に抑えたいと思います。だから私はこれが可能であることをオフのチャンスに、ここで聞いてるのよ(私は真剣にそれは疑う。)

は、このようなテーブル構造と仮定:あり(コントローラーをテストするために

id - int(10), auto_increment, primary_key, not null 
parent_id - int(10), null 
model - varchar(255), utf8_bin, null 
foreign_key - int(10), null 
alias - varchar(255), utf8_bin, null, 
lft - int(10), null 
rght - int(10), null 

といくつかのレコードをルートノードと、私は間違っLFTとrghtの値を取得する可能性があります):

1, null, null, null, controllers,   1, 14 
2, 1, null, null, one_test_controllers, 2, 7 
3, 2, null, null, one_action,   3, 4 
4, 2, null, null, two_action,   5, 6 
5, 1, null, null, two_test_controllers, 8, 13 
6, 5, null, null, one_action,   9, 10 
7, 5, null, null two_action,   11, 12 

そして、2つのテストパス:

$test1 = '/controllers/one_test_controller/two_action'; 
$test2 = '/controllers/two_test_controller/two_action'; 

以上の関連に最も関連性の高いからIDの配列を返し、これらの結果を与える:

// Result 1 
array(
    0 => 4, 
    1 => 2, 
    2 => 1 
) 

// Result 2 
array(
    0 => 7, 
    1 => 5, 
    2 => 1 
) 

私が現在やっていること)(爆発(この例では$ test1のを使用して)へのパスと配列を、INGのある最初のエイリアス "two_action"と一致するすべてのレコードを検索します。結果をループして、最後の結果の親IDと一致し、 "one_test_controller"の別名を持つすべてのレコードを検索します。その後、parent_id = 0まで繰り返します。

これはうまくいきますが、明らかに複数の再帰的なSQLクエリは理想的ではありませんが、これを手伝ってくれる魔法のSQLクエリはありますか?それとも、これが最高のものだと仮定して私は正しいのですか?

答えて

2

eh?隣接ツリーを使用してパスを解析することによって、データをフェッチする構造をすでに持っています。

ただし、完全なパスを保存せずに/固有のノード名を必要とする場合は、ボトムアップから検索することはできません。検討する - 両方のテストケースでは、 'two_action'から始めて2つの異なるリーフを探しています。あなたが....

SELECT ancestors.* 
FROM ahier ancestors, 
(SELECT lft, rght 
    FROM ahier ref 
    WHERE ref.path='/controllers/one_test_controller/two_action') ilv 
WHERE (ancestors.lft >= ilv.left AND ancestors.rght <= ilv.rght) 
ORDER BY ancestors.lft ASC; 

またはIDを使用してテーブル内のパス全体を保存する(またはあなたのクエリからidでノードを参照することができる)場合:代わり

SELECT ancestors.* 
FROM ahier ancestors, 
(SELECT lft, rght 
    FROM ahier ref 
    WHERE ref.id=4) ilv 
WHERE (ancestors.lft >= ilv.left AND ancestors.rght <= ilv.rght) 
ORDER BY ancestors.lft ASC; 

、あなたが書くことができます特定のノードの別名を持つすべての可能なパスを返すために、クエリ - それはどちらか非常に効率的ではないだろう....

SELECT treenum, ancestors.* 
FROM ahier ancestors, 
(SELECT lft, rght, id as treenum 
    FROM ahier ref 
    WHERE ref.alias='two_action') ilv 
WHERE (ancestors.lft >= ilv.left AND ancestors.rght <= ilv.rght) 
ORDER BY treenum, ancestors.lft ASC; 

を(およびそのparent_idsからLFTとrghtを再構築するenought簡単)

+0

ありがとう、私はそれを受け入れるでしょう。残念ながら私はテーブルを変更できません。 CakePHPシェルスクリプトによって生成されたスキーマと互換性がなければなりません。 – rich97

関連する問題