私は最近、ネストされたセットモデルのがらくたを使用しています。私は、ほぼすべての有用な操作とビューのクエリを楽しく設計してきました。私が行き詰まっていることの 1 つは、ノードの直接の子 (および子のみであり、それ以上の子孫ではない!) を選択する方法です。
正直なところ、私はその方法を知っていますが、それには手に負えない量の SQL が含まれます。もっと簡単な解決策があると確信しています。
私は最近、ネストされたセットモデルのがらくたを使用しています。私は、ほぼすべての有用な操作とビューのクエリを楽しく設計してきました。私が行き詰まっていることの 1 つは、ノードの直接の子 (および子のみであり、それ以上の子孫ではない!) を選択する方法です。
正直なところ、私はその方法を知っていますが、それには手に負えない量の SQL が含まれます。もっと簡単な解決策があると確信しています。
投稿した記事は読みましたか?「ノードの直接の下位を検索する」という見出しの下にあります。
SELECT node.name, (COUNT(parent.name) - (sub_tree.depth + 1)) AS depth
FROM nested_category AS node,
nested_category AS parent,
nested_category AS sub_parent,
(
SELECT node.name, (COUNT(parent.name) - 1) AS depth
FROM nested_category AS node,
nested_category AS parent
WHERE node.lft BETWEEN parent.lft AND parent.rgt
AND node.name = 'PORTABLE ELECTRONICS'
GROUP BY node.name
ORDER BY node.lft
)AS sub_tree
WHERE node.lft BETWEEN parent.lft AND parent.rgt
AND node.lft BETWEEN sub_parent.lft AND sub_parent.rgt
AND sub_parent.name = sub_tree.name
GROUP BY node.name
HAVING depth <= 1
ORDER BY node.lft;
ただし、私がしていること (これは不正行為です) は、ネストされたセットを隣接リストと組み合わせることです。テーブルに「parent_id」を埋め込むので、ノードの子を簡単に要求できます。
これは、サブクエリや親列の冗長性がなくても簡単に実行できるはずです! たとえば、親の左と右がすでにわかっている場合:
SELECT child.id
FROM nodes AS child
LEFT JOIN nodes AS ancestor ON
ancestor.left BETWEEN @parentleft+1 AND @parentright-1 AND
child.left BETWEEN ancestor.left+1 AND ancestor.right-1
WHERE
child.left BETWEEN @parentleft+1 AND @parentright-1 AND
ancestor.id IS NULL
つまり、「問題のノードのすべての子孫から、それら自身とノードの間に祖先がないものを選択する」ということです。
これはより良く、より小さくなります
ユーザー「bobince」はほとんどそれを持っていました。私はそれを理解し、それが私のために機能するようになりました。なぜなら、私はほとんどの場合よりも少し多くのMySQLの経験を持っているからです。しかし、ボビンスの答えが人々を怖がらせる理由はわかります。彼の質問は不完全です。最初に、mysql変数でparent_leftとparent_rightを選択する必要があります。
tree
以下の2つのクエリは、テーブルの名前が、左の列の名前がlft
、右の列の名前rgt
が、主キーの名前がであると想定していますid
。ニーズに合わせてこれらの値を変更してください。また、最初のselectステートメントを調べます。ノード5の直系の子孫を検索していることがわかります。番号5を変更して、必要なノードの子を検索します。
個人的には、これはこれまでに提示された他のクエリよりも洗練され、セクシーで、効率的なクエリだと思います。
SELECT `lft`, `rgt` INTO @parent_left, @parent_right FROM efm_files WHERE `id` = 5;
SELECT `child`.`id`
FROM `tree` AS `child`
LEFT JOIN `tree` AS `ancestor` ON
`ancestor`.`lft` BETWEEN @parent_left+1 AND @parent_right-1 AND
`child`.`lft` BETWEEN `ancestor`.`lft`+1 AND `ancestor`.`rgt`-1
WHERE
`child`.`lft` BETWEEN @parent_left+1 AND @parent_right-1 AND
`ancestor`.`id` IS NULL
ウィキペディアのリンクには、選択した回答とともに、適切な最小化されたバージョンの回答があることがわかりました。
SELECT DISTINCT Child.Name
FROM ModelTable AS Child, ModelTable AS Parent
WHERE Parent.Lft < Child.Lft AND Parent.Rgt > Child.Rgt -- associate Child Nodes with ancestors
GROUP BY Child.Name
HAVING MAX(Parent.Lft) = @parentId -- Subset for those with the given Parent Node as the nearest ancestor
そして、Linqでそれを表現しようとする人は、リンクに従ってください: https://stackoverflow.com/a/25594386/361100
深度列も使用します。しかし、使用
SELECT Child.Node, Child.LEFT, Child.RIGHT
FROM Tree AS Child, Tree AS Parent
WHERE
Child.Depth = Parent.Depth + 1
AND Child.LEFT > Parent.LEFT
AND Child.RIGHT < Parent.RIGHT
AND Parent.LEFT = 1 -- Given Parent Node Left Index
私はnecroの投稿をしていることを知っていますが、これが私の意見です。
ネストされたセットに「深さ」列を含めてみませんか? 深さの列はアイテムの「レベル」を示します。
したがって、アイテムの直接の子を選択するには、次のようにします
select c.*
from tree as p
join tree as c on (c.left > p.left and c.right < p.right and c.depth = p.dept + 1)
where p.id = @parentID