我尝试创建SQL查询以在删除父记录时删除子记录 问题是,孩子和父母都存放在同一张桌子里 这是(简化的)数据模型:
ThingTable
ID | Name | ParentID
1000 | Thing1 | NULL
1001 | Thing2 | 1000
1002 | Thing3 | 1000
1003 | Thing4 | 1000
1004 | Thing5 | 1003
ChildThingTable
ID | Color
1001 | Blue
1002 | Black
1003 | Green
1004 | Red
假设删除了ID 1000(父级),我需要从ChildThingTable和ThingTable中删除相应的记录。
我唯一的限制是我不能以任何方式使用触发器或改变底层数据库结构。
这是我编写的伪代码,但我在将其转换为SQL时遇到了困难:
非常感谢任何帮助!
答案 0 :(得分:0)
添加约束是否构成'以任何方式改变底层数据库结构'
因为我会考虑使用带有级联Delete的约束,这将要求Parent Id列是ID表的外键,然后在删除主键时添加约束,匹配的外键将被删除太
ALTER TABLE dbo.T2
ADD CONSTRAINT FK_T1_T2_Cascade
FOREIGN KEY (EmployeeID) REFERENCES dbo.T1(EmployeeID) ON DELETE CASCADE
还有递归查询可以做类似的事情,但我会从这开始。
然后这样的事情应该有效 http://en.wikipedia.org/wiki/Hierarchical_and_recursive_queries_in_SQL
DELETE
FROM thingtable START WITH ID = 1000
CONNECT BY PRIOR ID = ParentID;
答案 1 :(得分:0)
如果我理解你的问题,这个程序应该这样做......
CREATE PROCEDURE DeleteThing
@IdToDelete INT
AS
BEGIN
DELETE ChildThingTable
WHERE ID IN ( SELECT ID FROM ThingTable WHERE ParentId = @IdToDelete );
DELETE ChildThingTable
WHERE ID = @IdToDelete;
DELETE ThingTable
WHERE ParentID = @IdToDelete;
DELETE ThingTable
WHERE ID = @IdToDelete;
END;
您可能希望将其包装在事务中,以便整个操作成功或失败。
正如其他人所提到的,这正是你应该使用参照完整性结构(外键)的原因。它们的存在有助于防止无效数据。
答案 2 :(得分:0)
您可以使用公用表表达式来递归
-- Begin Create Test Data
SET NOCOUNT ON
CREATE TABLE #ThingTable (
ID INT NOT NULL,
[Name] VARCHAR(255) NOT NULL,
[ParentID] INT NULL
)
CREATE TABLE #ChildThingTable (
ID INT NOT NULL,
[Color] VARCHAR(255) NOT NULL,
)
INSERT INTO #ThingTable (ID,[Name],ParentID) VALUES (1000,'Thing1',NULL)
INSERT INTO #ThingTable (ID,[Name],ParentID) VALUES (1001,'Thing2',1000)
INSERT INTO #ThingTable (ID,[Name],ParentID) VALUES (1002,'Thing3',1000)
INSERT INTO #ThingTable (ID,[Name],ParentID) VALUES (1003,'Thing4',1000)
INSERT INTO #ThingTable (ID,[Name],ParentID) VALUES (1004,'Thing5',1003)
INSERT INTO #ChildThingTable ( ID, Color ) VALUES ( 1001 , 'Blue')
INSERT INTO #ChildThingTable ( ID, Color ) VALUES ( 1002 , 'Black')
INSERT INTO #ChildThingTable ( ID, Color ) VALUES ( 1003 , 'Green')
INSERT INTO #ChildThingTable ( ID, Color ) VALUES ( 1004 , 'Red')
SET NOCOUNT OFF
GO
-- End Create Test Data
-- This is a batch, but could easily be a stored procedure.
DECLARE @InputID INT
SET @InputID = 1000;
SET NOCOUNT ON
DECLARE @Temp TABLE(ID INT NOT NULL);
WITH ThingCTE (ID, ParentID, [Level])
AS
(
SELECT tt1.ID, tt1.ParentID, 1 AS [Level]
FROM #ThingTable tt1
WHERE tt1.ID = @InputID
UNION ALL
SELECT tt2.ID, tt2.ParentID, tc1.[Level]+1
FROM #ThingTable tt2
JOIN ThingCTE tc1 ON (tt2.ParentID = tc1.ID)
)
INSERT INTO @Temp
( ID )
SELECT ID
FROM ThingCTE
SET NOCOUNT OFF
DELETE ctt
-- Output is for debug purposes, should be commented out in production.
OUTPUT Deleted.*
FROM #ChildThingTable ctt
JOIN @Temp t ON (ctt.ID = t.ID);
DELETE tt
-- Output is for debug purposes, should be commented out in production.
OUTPUT Deleted.*
FROM #ThingTable tt
JOIN @Temp t ON (tt.ID = t.ID)
DROP TABLE #ChildThingTable;
DROP TABLE #ThingTable;
答案 3 :(得分:0)
尝试使用递归cte一直爬到root,所以每个东西都不仅显示在ParentID上,而且显示在父级的ParentID上等等。
CREATE TABLE Things (
ID INT NOT NULL,
[Name] VARCHAR(255) NOT NULL,
[ParentID] INT NULL
);
INSERT INTO Things (ID,[Name],ParentID)
select 1000,'Thing1',NULL union all
select 1001,'Thing2',1000 union all
select 1002,'Thing3',1000 union all
select 1003,'Thing4',1002 union all
select 1004,'Thing5',1003;
注意我已经为你的数据添加了一个级别,以显示我们可以一直到顶部,所以Thing5的父级是Thing4,其父级是Thing3,其父级是Thing1。
with
Parents( ID, Name, ParentID, GrandParentID )
as(
select t1.ID, t1.Name, t2.ID, t2.ParentID
from Things t1
left join Things t2
on t2.id = t1.ParentID
union all
select t1.ID, t1.Name, p.ParentID, p.GrandParentID
from Things t1
join Parents p
on p.ID = t1.ParentID
where p.ParentID is not null or p.GrandParentID is not null
)
select ID, Name, ParentID
from Parents
order by ID, ParentID desc;
产生类似 Fiddle 的输出:
ID NAME PARENTID
==== ====== ========
1000 Thing1 (null)
1001 Thing2 1000
1002 Thing3 1000
1003 Thing4 1002
1003 Thing4 1000
1004 Thing5 1003
1004 Thing5 1002
1004 Thing5 1000
因此,如果您删除了Thing3(ID 1002),那么也会在上面的ParentID列(Thing4和Thing5)中删除1002的所有内容。
从子表中删除孤儿很简单:左边连接回事物表并删除所有找不到匹配项的东西。