ネストされたセットツリー全体をソートするのに役立つ次のコードを書き終えました。
並べ替えには (理想的には) ツリー内の各ノードの現在のレベルを一覧表示するビューと、2 つのノードを交換するための手順が必要です。両方とも以下に含まれています。兄弟スワップ コードは、Joe Celkos の「Tree & Hierarchies」の本から入手することを強くお勧めします。ネストされたセットを使用しているすべての人に。
並べ替えは、'INSERT INTO @t' ステートメントで変更できます。ここでは、'Name' の単純な英数字の並べ替えです。
これは、特にセットベースのコードにカーソルを使用する方法としては不十分かもしれませんが、私にとってはうまくいくと言っているので、役に立てば幸いです。
アップデート:
以下のコードは、cusor を使用せずにバージョンを表示するようになりました。約 10 倍の速度向上が見られます
CREATE VIEW dbo.tree_view
AS
SELECT t2.NodeID,t2.lft,t2.rgt ,t2.Name, COUNT(t1.NodeID) AS level
FROM dbo.tree t1,dbo.tree t2
WHERE t2.lft BETWEEN t1.lft AND t1.rgt
GROUP BY t2.NodeID,t2.lft,t2.rgt,t2.Name
GO
----------------------------------------------
DECLARE @CurrentNodeID int
DECLARE @CurrentActualOrder int
DECLARE @CurrentRequiredOrder int
DECLARE @DestinationNodeID int
DECLARE @i0 int
DECLARE @i1 int
DECLARE @i2 int
DECLARE @i3 int
DECLARE @t TABLE (TopLft int,NodeID int NOT NULL,lft int NOT NULL,rgt int NOT NULL,Name varchar(50),RequiredOrder int NOT NULL,ActualOrder int NOT NULL)
INSERT INTO @t (toplft,NodeID,lft,rgt,Name,RequiredOrder,ActualOrder)
SELECT tv2.lft,tv1.NodeID,tv1.lft,tv1.rgt,tv1.Name,ROW_NUMBER() OVER(PARTITION BY tv2.lft ORDER BY tv1.ColumnToSort),ROW_NUMBER() OVER(PARTITION BY tv2.lft ORDER BY tv1.lft ASC)
FROM dbo.tree_view tv1
LEFT OUTER JOIN dbo.tree_view tv2 ON tv1.lft > tv2.lft and tv1.lft < tv2.rgt and tv1.level = tv2.level+1
WHERE tv2.rgt > tv2.lft+1
DELETE FROM @t where ActualOrder = RequiredOrder
WHILE EXISTS(SELECT * FROM @t WHERE ActualOrder <> RequiredOrder)
BEGIN
SELECT Top 1 @CurrentNodeID = NodeID,@CurrentActualOrder = ActualOrder,@CurrentRequiredOrder = RequiredOrder
FROM @t
WHERE ActualOrder <> RequiredOrder
ORDER BY toplft,requiredorder
SELECT @DestinationNodeID = NodeID
FROM @t WHERE ActualOrder = @CurrentRequiredOrder AND TopLft = (SELECT TopLft FROM @t WHERE NodeID = @CurrentNodeID)
SELECT @i0 = CASE WHEN c.lft < d.lft THEN c.lft ELSE d.lft END,
@i1 = CASE WHEN c.lft < d.lft THEN c.rgt ELSE d.rgt END,
@i2 = CASE WHEN c.lft < d.lft THEN d.lft ELSE c.lft END,
@i3 = CASE WHEN c.lft < d.lft THEN d.rgt ELSE c.rgt END
FROM dbo.tree c
CROSS JOIN dbo.tree d
WHERE c.NodeID = @CurrentNodeID AND d.NodeID = @DestinationNodeID
UPDATE dbo.tree
SET lft = CASE WHEN lft BETWEEN @i0 AND @i1 THEN @i3 + lft - @i1
WHEN lft BETWEEN @i2 AND @i3 THEN @i0 + lft - @i2
ELSE @i0 + @i3 + lft - @i1 - @i2
END,
rgt = CASE WHEN rgt BETWEEN @i0 AND @i1 THEN @i3 + rgt - @i1
WHEN rgt BETWEEN @i2 AND @i3 THEN @i0 + rgt - @i2
ELSE @i0 + @i3 + rgt - @i1 - @i2
END
WHERE lft BETWEEN @i0 AND @i3
AND @i0 < @i1
AND @i1 < @i2
AND @i2 < @i3
UPDATE @t SET actualorder = @CurrentRequiredOrder where NodeID = @CurrentNodeID
UPDATE @t SET actualorder = @CurrentActualOrder where NodeID = @DestinationNodeID
DELETE FROM @t where ActualOrder = RequiredOrder
END