2011-05-28 9 views
5

私はid,depth,parent_idおよびpathに基づいてmysqlテーブルにツリー表現をしています。 ルートのレコードは、0の左に埋め込まれたIDの16進値に基づく0,parent_id != nullおよびpathの表現を有しています。同じパス内の最短文字列(ブランチ)

ツリーのすべての要素を指定することによって構成されdepth = parent.depth + 1、例えばpath = parent.path + hex(id)parent_id = parent.id(擬似コード):

id path   depth parent_id assigned_user_id 
------------------------------------------------------------ 
1  001    0  NULL   NULL 
2  002    0  NULL   1 
3  001003   1  1   2 
4  002004   1  2   1 
5  001003005  2  3   2 
6  001003005006 3  5   2 
7  002004007  2  4   1 
8  002004008  2  4   2 
9  002004009  2  4   2 
10 00200400800A 3  8   2 

のように... 問題は、特定のユーザーのレコードを取得する方法です同一の支店の最短経路に限定されたID。例えばassigned_user_id = 2 retriveのために:

id path   depth parent_id assigned_user_id 
------------------------------------------------------------ 
3  001003   1  1   2 
8  002004008  2  4   2 
9  002004009  2  4   2 

の代わりに:

id path   depth parent_id assigned_user_id 
------------------------------------------------------------ 
3  001003   1  1   2 
5  001003005  2  3   2 
6  001003005006 3  5   2 
8  002004008  2  4   2 
9  002004009  2  4   2 
10 00200400800A 3  8   2 
+0

わかりません。最短パスが必要ですが、希望する出力にはパス長の異なる複数のレコードがあります。レコードを選択する基準が何であるかを明確にしてください。 – Krab

+0

@Krabパスの先頭は等しくなければなりません。コメントありがとう、私は私の質問を更新します。 – veritas

+1

基本的に、私はその質問を理解していると思う。私はあなたにこの状況を詳しく説明してほしい。パス「001003」と「001003005006」で定義された項目がユーザ「2」に割り当てられ、「001003005」がユーザ「1」に割り当てられているとする。 '001003005006'が' 001003'で始まるという理由だけで '001003005006'を却下するのは正しいでしょうか?言い換えれば、レベルの隣接性(深度)を考慮に入れる必要がありますか? –

答えて

2
SELECT t1.* 
FROM atable t1 
    LEFT JOIN atable t2 
    ON t2.assigned_user_id = t1.assigned_user_id AND 
     t2.path = LEFT(t1.path, CHAR_LENGTH(t2.path)) AND 
     t2.id <> t1.id 
WHERE t1.assigned_user_id = 2 
    AND t2.id IS NULL 
+0

それはhttp://stackoverflow.com/questions/6162527/shortest-string-within-same-path-branch/6162874#6162874よりも最適なソリューションだと思われます。また有効です) – veritas

0

あなたはこのような何かを試してみましたか?

select child.assigned_user_id, child.id 
from node as child 
left join node as parent 
on child.path like CONCAT(parent.path, '%') 
and child.assigned_user_id = parent.assigned_user_id 
and child.id <> parent.id 
group by child.assigned_user_id, child.id 
having max(parent.id is null) = true 

(それは全く同様に動作しますが、基本的にはわからない:親の完全なリストを抽出するために、パスに参加するために残され、その後、あなただけ保つように集約しますassigned_user_idによってグループ化された任意の親のないノード)

1

私はこのような何かをしようとするだろう:。

SELECT * FROM PATHS WHERE ASSIGNED_USER_ID = 2 
AND NOT PARENT_ID IN (SELECT ID FROM PATHS WHERE ASSIGNED_USER_ID = 2) 

基本的な考え方は、特定のユーザーのためにトップの親ノードを選択することです。

2

私が正しいと思えば、選択したIDの中にparent_idが含まれる行を除外すれば十分でしょう。これは、親と子が選択された場合、それらは同じブランチになければならないからです。親のパスは短くなるため、子を除外しても問題ありません。以下のような

何か:あなたはこのようなツリーを持っているでしょう

SELECT * 
    FROM x 
    WHERE assigned_user_id = 2 
     AND parent_id NOT IN (SELECT id FROM x WHERE assigned_user_id = 2) 

場合(番号で割り当てられたユーザーID):

A1     G2 
/\     /\ 
B2 C2    H2 I2 
    | \    | | \ 
    D2 E2   L1 J2 K2 
         | 
         M2 

B2は、C2は、G2およびM2が選択されることになります。私はこれがあなたの意図かどうかまだ分かりません。

+0

このアイデアもありましたが、機能しません。例:M2の子としてノードN2があるとします。 – Wolfgang

+0

ニース、+1。私は、パスの文字列を処理し、深さレベルを考慮して考えていましたが、あなたのアプローチははるかに簡単に見えます。私はそれがより好きです。 –

+0

@Wolfgang:なぜ、このスクリプトでは「N2」が出現するとは思わないのですか? –

1

AはAがBで始まっていればBよりも短いです。これは「これで始まる」ということに似ているかもしれません。

SELECT a.* FROM node AS a 
WHERE a.assigned_user_id = ? 
AND NOT EXIST 
(SELECT * FROM node AS b 
    WHERE b.assigned_user_id = ? 
    AND LENGTH(a.path) > LENGTH(b.path) 
    AND a.path LIKE CONCAT(b.path, '%')) 

どちらも?所望のユーザIDにマッピングされる。

EDITはassigned_user_idを含むことを忘れました。コードを変更しました。

2 EDIT = Bの場合を回避する

変更コード。

+0

空の結果:( – veritas

+0

あなたは正しいですが内側の選択はまたb = aを見つけるでしょうそれを修正しようとします – Wolfgang

+0

働く100% :)しかし、私はすべてのソリューションを分析しています – veritas

関連する問題