SQL لإعادة ترتيب العقد في التسلسل الهرمي
-
02-07-2019 - |
سؤال
لدي قاعدة بيانات "قائمة المهام" التي تستخدم نموذج القائمة المجاورة (انظر أدناه) بحيث يمكن أن تحتوي كل "مهمة" على مهام فرعية غير محدودة.يحتوي الجدول على عمود "TaskOrder" بحيث يتم عرض كل شيء بالترتيب الصحيح في طريقة عرض الشجرة.
هل هناك عبارة SQL (MS-SQL 2005) من شأنها تحديد كافة العقد الفرعية لأحد الوالدين المحدد وتحديث عمود TaskOder عند حذف أحد الأخوة؟
Task Table ---------- TaskId ParentTaskId TaskOrder TaskName --etc--
أيه أفكار؟شكرًا.
المحلول
طريقتان مختلفتان...نظرًا لأن TaskOrder يتم تحديد نطاقه بواسطة المعرف الأصلي، فليس من الصعب جدًا جمعه.في SQL Server، قمت بوضع مشغل على الحذف الذي يقلل جميع العناصر "الأعلى" من تلك التي قمت بحذفها، وبالتالي إغلاق الفجوة (يتبع الكود الكاذب):
CREATE TRIGGER ON yourtable FOR DELETE
AS
UPDATE Task
SET TaskOrder = TaskOrder - 1
WHERE ParentTaskId = deleted.ParentTaskId
AND TaskOrder > deleted.TaskOrder
إذا كنت لا تريد مشغلاً، فيمكنك التقاط معرف الوالدين وTaskOrder في استعلام أولاً، وحذف الصف، ثم تنفيذ بيان التحديث نفسه ولكن باستخدام القيم الحرفية بدلاً من المشغل.
أو إذا كنت تريد تقليل رحلات الخادم ذهابًا وإيابًا إلى الحد الأدنى، فيمكنك نقل المهمة المراد حذفها إلى الأسفل، ثم نقل المهام الأخرى إلى الأعلى، ثم القيام بالحذف، ولكن هذا يبدو معقدًا للغاية.
نصائح أخرى
إذا كنت تستخدم TaskOrder فقط للفرز، فمن المؤكد أنه سيكون من الأسهل ببساطة ترك الثغرات الموجودة في TaskOrder، لأن مجرد حذف العناصر لن يجعل الفرز غير صحيح.ولكن بعد ذلك لست متأكدًا من احتياجات تطبيقك.
لا مباشرة.هذا ال الترتيب الطوبولوجي حيث تقوم "بتعليق" العقد الفرعية من أحد الوالدين.إذا لم يكن هناك تبعية داخل الأطفال، فلا يهم ترتيب إعدامهم.إذا كان يجب إعدام الأطفال بترتيب معين، فلن يكون لديك معلومات كافية لاستنتاج ذلك - فيجب أن يكون لديهم مستويات إضافية من التسلسل الهرمي.
على افتراض أن ترتيب الأطفال داخل أحد الوالدين لا علاقة له بالموضوع، فإن النوع السياسي سوف يحقق لك ما تريد.لن تتمكن من إدخال هذا في استعلام واحد في معظم لهجات SQL - سيتعين عليك كتابة sproc للقيام بذلك.
إذا كان ترتيب العناصر الفرعية داخل العقدة ذا صلة، فأنت بحاجة إلى الحفاظ على ترتيب المهام داخل العقدة الأم.سيؤدي الاستعلام باستخدام ParentNodeID وTaskOrder والعدد (*) إلى اختيار التكرارات، ولكن ما لم يكن لدى النظام معلومات إضافية لطلب المهام، فستظل بحاجة إلى التدخل اليدوي لتحديد الترتيب الصحيح.
الرجاء إضافة تعليقات إذا كنت تريد مني توضيح شيء ما.
تبدو هذه مهمة لـ 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;
بالطبع، يمكنك حذف الحذف، وترك السجل موجودًا لأغراض إعداد التقارير المستقبلية.
تنبيه قضائي:لم تختبر!!!