階層内のノードを並べ替えるSQL
-
02-07-2019 - |
質問
隣接リストモデル(下記参照)を使用する「タスクリスト」データベースがあるため、各「タスク」には無制限のサブタスクを含めることができます。テーブルには「TaskOrder」列があるため、すべてがツリービューで正しい順序でレンダリングされます。
指定された親のすべての子ノードを選択し、兄弟が削除されたときにTaskOder列を更新するSQLステートメント(MS-SQL 2005)はありますか?
Task Table ---------- TaskId ParentTaskId TaskOrder TaskName --etc--
アイデアはありますか?ありがとう。
解決
さまざまな方法の組み合わせ... TaskOrderのスコープは親IDであるため、収集するのはそれほど難しくありません。 SQL Serverでは、削除したトリガーよりも「高い」すべてのものをデクリメントし、それによってギャップを埋めるトリガーを削除に設定します(疑似コードが続きます)。
CREATE TRIGGER ON yourtable FOR DELETE
AS
UPDATE Task
SET TaskOrder = TaskOrder - 1
WHERE ParentTaskId = deleted.ParentTaskId
AND TaskOrder > deleted.TaskOrder
トリガーが必要ない場合は、最初にクエリでparentIDとTaskOrderをキャプチャし、行を削除してから、同じ更新ステートメントを実行しますが、トリガーではなくリテラルを使用します。
またはサーバーの往復を最小限に抑えたい場合は、削除するタスクを一番下まで移動し、他のタスクを上に移動してから削除を実行できますが、これは非常に複雑に思えます。
他のヒント
並べ替えにTaskOrderのみを使用している場合、単純にアイテムを削除しても並べ替えが不正確になることはないため、TaskOrderに穴を空けるのは確かに簡単です。ただし、アプリケーションのニーズについてはわかりません。
直接ではありません。これはトポロジカルソートで、子ノードを親から「ぶら下げ」ています。子内に依存関係がない場合、子が実行される順序は重要ではありません。子を特定の順序で実行する必要がある場合、これを推測するのに十分な情報がありません。追加の階層レベルが必要になります。
親の中の子の順序が無関係であると仮定すると、政治的なソートはあなたが望むものを得るでしょう。ほとんどのSQL方言では、これを単一のクエリに含めることはできません。それを行うには、sprocを記述する必要があります。
ノード内の子の順序が関連する場合、親内でタスクの順序を維持する必要があります。 ParentNodeID、TaskOrder、およびcount(*)を使用するクエリは重複を選択しますが、タスクを順序付けるための追加情報がシステムにない限り、正しい順序を選択するには手動による介入が必要になります。
何か明確にしたい場合はコメントを追加してください。
これはROW_Numberの仕事のように見えます。
DECLARE @Tasks TABLE
(
TaskId int PRIMARY KEY,
ParentTaskId int,
TaskOrder int,
TaskName varchar(30)
)
INSERT INTO @Tasks(TaskId, ParentTaskId, TaskOrder, TaskName)
SELECT 1, null, 1, 'ParentTask'
INSERT INTO @Tasks(TaskId, ParentTaskId, TaskOrder, TaskName)
SELECT 2, 1, 2, 'B'
INSERT INTO @Tasks(TaskId, ParentTaskId, TaskOrder, TaskName)
SELECT 3, 1, 1, 'A'
INSERT INTO @Tasks(TaskId, ParentTaskId, TaskOrder, TaskName)
SELECT 4, 1, 3, 'C'
--Initial
SELECT * FROM @Tasks WHERE ParentTaskId = 1 ORDER BY TaskOrder
DELETE FROM @Tasks WHERE TaskId = 2
--After Delete
SELECT * FROM @Tasks WHERE ParentTaskId = 1 ORDER BY TaskOrder
UPDATE t
SET TaskOrder = NewTaskOrder
FROM @Tasks t
JOIN
(
SELECT TaskId, ROW_Number() OVER(ORDER BY TaskOrder) as NewTaskOrder
FROM @Tasks
WHERE ParentTaskId = 1
) sub ON t.TaskId = sub.TaskId
--After Update
SELECT * FROM @Tasks WHERE ParentTaskId = 1 ORDER BY TaskOrder
タスク88の削除:
UPDATE TaskTable
SET ParentTaskID = (SELECT ParentTaskID AS temp FROM Task_Table t1 WHERE TaskID = 88)
WHERE
TaskID IN (SELECT TaskID task2 FROM TaskTable t2 WHERE ParentTaskID = 88);
Delete FROM TaskTable WHERE TaskID = 88;
もちろん、削除を削除して、将来のレポート目的のためにレコードを残しておくこともできます。
警告:テストされていません!!!