PDA

View Full Version : حذف نودها به صورت بازگشتی با استفاده از Tsql



bftarane
شنبه 25 خرداد 1392, 18:59 عصر
سلام.
فرض کنید جدول زیر رو داریم
105604
که به شکل زیر در treeview نمایش داده میشه
105605
حالا فرض کنید می خواهیم وقتی کاربر مثلاً روی ماشین کلیک کرد و دکمه حذف رو زد نود ماشین و تمام فرزندان آن حذف شوند در Tsql چطور میشه این کار رو در یه Sp انجام داد؟
ممنون.

tooraj_azizi_1035
شنبه 25 خرداد 1392, 19:30 عصر
سلام
فرصت نکردم تست کنم احتمالاً جواب میده توضیحش در لینک هست:http://msdn.microsoft.com/en-us/library/ms186243(v=sql.105).aspx (http://msdn.microsoft.com/en-us/library/ms186243%28v=sql.105%29.aspx)


USE AdventureWorks2008R2;
GO
WITH DirectReports (ManagerID, EmployeeID, Title, DeptID, Level)
AS
(
-- Anchor member definition
SELECT e.ManagerID, e.EmployeeID, e.Title, edh.DepartmentID,
0 AS Level
FROM dbo.MyEmployees AS e
INNER JOIN HumanResources.EmployeeDepartmentHistory AS edh
ON e.EmployeeID = edh.BusinessEntityID AND edh.EndDate IS NULL
WHERE ManagerID =0
UNION ALL
-- Recursive member definition
SELECT e.ManagerID, e.EmployeeID, e.Title, edh.DepartmentID,
Level + 1
FROM dbo.MyEmployees AS e
INNER JOIN HumanResources.EmployeeDepartmentHistory AS edh
ON e.EmployeeID = edh.BusinessEntityID AND edh.EndDate IS NULL
INNER JOIN DirectReports AS d
ON e.ManagerID = d.EmployeeID
)
-- Statement that executes the CTE
DELETE FROM
FROM dbo.MyEmployees WHERE EmployeeID IN (SELECT EmployeeID FROM DirectReports)
GO


شرط WHERE که Bold کردم به جای 0 باید کد پدر رو بدید یعنی 19.
توضیح اینکه کد سعی می کنه با CTE بازگشتی بیاد از پدر تا همه فرزندان جلو بره و همه رکوردها رو بدست بیاره بعد با استفاده از نتیجه ای که در دست داریم (DirectReports) میاد رکوردها رو حذف میکنه. این کوئری از مثال درون لینک برگرفته شده.

alireza_s_84
شنبه 25 خرداد 1392, 19:30 عصر
سلام.
فرض کنید جدول زیر رو داریم
105604
که به شکل زیر در treeview نمایش داده میشه
105605
حالا فرض کنید می خواهیم وقتی کاربر مثلاً روی ماشین کلیک کرد و دکمه حذف رو زد نود ماشین و تمام فرزندان آن حذف شوند در Tsql چطور میشه این کار رو در یه Sp انجام داد؟
ممنون.

سلام اساس طراحی دیتابیس شما مشکل داره
وقتی چند گروه برای ماشین داریم پس میبایست گروه ها در یک جدول جداگانه باشد (این یعنی نرمال سازی)
بعد زیرشاخه های هر گروه هم در یک جدول باشند
بعد خیلی راحت میتونید با داشتن یک شاخه تمامی زیرشاخه های اون رو حذف کنید

tooraj_azizi_1035
شنبه 25 خرداد 1392, 19:40 عصر
سلام اساس طراحی دیتابیس شما مشکل داره
وقتی چند گروه برای ماشین داریم پس میبایست گروه ها در یک جدول جداگانه باشد (این یعنی نرمال سازی)
بعد زیرشاخه های هر گروه هم در یک جدول باشند
بعد خیلی راحت میتونید با داشتن یک شاخه تمامی زیرشاخه های اون رو حذف کنید
سلام
خوب اگه بخواهیم از Level 50 به بعد رو حذف کنیم یعنی فرضاً تعداد سطوح 100 مرحله عمق دارد و ما می خواهیم از سطح 50 ام به بعد رو حذف کنیم چه باید کرد؟
چیزی که شما می گید زمانی خوبه که همیشه از بالاترین سطح بخوایم عمل حذف رو انجام بدیم.
البته شاید خواسته bftrane هم این باشه.
ما SELF JOIN هم داریم که برای این سناریو پیش بینی شده. یعنی پدر فرزند. و البته نوع داده ای hierarchyid که از همه بهتر و سریعتر عمل می کنه.

bftarane
شنبه 25 خرداد 1392, 20:28 عصر
چیزی که شما می گید زمانی خوبه که همیشه از بالاترین سطح بخوایم عمل حذف رو انجام بدیم.
البته شاید خواسته bftrane هم این باشه.نه خواسته من این نیست من می خوام کاربر روی هر نودی که کلیک کرد اون نود به همراه تمام فرزندانش حذف بشه اگه هم فرزند نداشت که به تنهایی حذف بشه.

ممنون مثالی که گذاشتید یه مقدار به نظرم پیچیده میرسه، امتحان میکنم اگه به نتیجه رسیدم اینجا مطرح میکنم.


سلام اساس طراحی دیتابیس شما مشکل داره
وقتی چند گروه برای ماشین داریم پس میبایست گروه ها در یک جدول جداگانه باشد (این یعنی نرمال سازی)
بعد زیرشاخه های هر گروه هم در یک جدول باشند
بعد خیلی راحت میتونید با داشتن یک شاخه تمامی زیرشاخه های اون رو حذف کنید فکر می کنم حالتی که شما می گین به درد وقتی می خوره که فقط دو سطح در کار باشه ولی در موردی که من گفتم منو داینامیک هست یعنی از قبل هیچ چیزی مشخص نیست و خود ادمین داده ها رو اضافه می کنه.

tooraj_azizi_1035
شنبه 25 خرداد 1392, 21:15 عصر
در مورد جدول شما در شرط WHERE قبل از UNION ALL باید MenuID که کد پدر هست مقداردهی بشه. که من اشتباهاً در بالا چیز دیگه ای گفتم.
و در مورد CTE بازگشتی اینکه عبارت پس از UNION ALL تا زمانی که هیچ رکوردی برنگردونه اجرا میشه. پس از اتمام اجرا کنترل به قسمت بعد از CTE یعنی دستور DELETE ارسال میشه.

bftarane
یک شنبه 26 خرداد 1392, 18:35 عصر
ممنون با کمک راهنماییهایی که در این پست شد و همچنین لینک زیر
http://stackoverflow.com/questions/1686340/sql-server-how-to-get-all-child-records-given-a-parent-id-in-a-self-referencing
من به جواب دلخواهم رسیدم
و کدهام به شکل زیر شد

DECLARE @ID INT

SELECT @ID =31

;WITH ret AS(
SELECT *
FROM TBLMenu
WHERE MenuID = @ID
UNION ALL
SELECT t.*
FROM TBLMenu t INNER JOIN
ret r ON t.ParentID = r.MenuID
)


DELETE
FROM dbo.TBLMenu WHERE MenuID IN (SELECT MenuID FROM ret)
GO