如何从包含自引用外键的表中删除所有数据

时间:2010-03-20 13:22:01

标签: sql sql-server database tsql

我有一张表,其中定义了员工关系。 即。

EmpID   Name  SeniorId
-----------------------
1         A      NULL
2         B       1
3         C       1
4         D       3

依旧......

其中,高级ID是外键,其主键表与引用列EmpId相同 我想清除此表中的所有行而不删除任何约束。我怎么能这样做?

删除需要像这样执行 4,3,2,1

我该怎么做

修改

Jhonny的答案对我有用,但哪些答案更有效。

5 个答案:

答案 0 :(得分:16)

我不知道我是否遗漏了某些东西,但也许你可以尝试一下。

UPDATE employee SET SeniorID = NULL
DELETE FROM employee

答案 1 :(得分:3)

如果表非常大(基数为数百万),并且不需要记录DELETE事务,则删除约束和TRUNCATEing并重新创建约束是迄今为止最有效的方法。此外,如果其他表中存在外键(并且在此特定表设计中似乎是这样),那么在所有情况下都必须首先删除这些行。

规范化没有提及递归/层次/树关系,所以我相信这是你回答DVK建议将其拆分成自己的表时的红色鲱鱼 - 这个表的垂直分区肯定是可行的还要考虑你是否可以利用它来获得我在下面列出的任何其他好处。正如DVK所暗示的,在这个特定的设计中,我经常看到一个单独的链接表来记录自我关系和其他类型的关系。这有很多好处:

  • 上下都有多对多而不是多对一(不常见,但可能有用)
  • 跟踪不同类型的直接关系 - 经理,导师,助理,薪资审批人,费用审批人,技术报告 - 关系和关系类型表中的行,而不是员工表中的新列
  • 通过在关系行中包含活动指标和生效日期,以时间上一致的方式跟踪更改层次结构(包括已终止的员工层次结构历史记录) - 只有在将关系规范化为自己的表时才能完全实现
  • 在SeniorID中没有NULL(实际上在任一ID上) - 这在避免错误逻辑方面是一个明显的优势,但是当你必须离开加入关系表时,NULL通常会出现在视图中
  • 更好的专用索引策略 - 而不是将SeniorID添加到Employee上已有的选定索引(特别是随着关系类型数量的增加)

当然,与这种关系有关的信息越多,就越强烈地表明关系本身就是一个表(即它是关系数据库中使用的真正意义上的“关系” - 相关数据存储在与主键相关的关系或表中,因此关系的正常形式可能强烈表明在employee表中创建关系表而不是简单的外键关系。

好处还包括其简单的删除方案:

DELETE FROM EmployeeRelationships;
DELETE FROM Employee;

你会注意到SO上接受的答案的惊人等价,因为在你的情况下,没有高级关系的员工有一个NULL - 所以在那个答案中,海报首先将所有设置为NULL以消除关系,然后删除员工。

TRUNCATE可能有适当的用法取决于约束(EmpployeeRelationships通常可以是TRUNCATEd,因为它的主键通常是复合而不是任何其他表中的外键)。

答案 2 :(得分:2)

试试这个

DELETE FROM employee;

答案 3 :(得分:1)

在循环内部,运行一个命令,删除具有未引用的EmpID的所有行,直到剩下零行为止。编写内部DELETE命令有多种方法:

 DELETE FROM employee WHERE EmpID NOT IN (SELECT SeniorID FROM employee)

 DELETE FROM employee e1 WHERE NOT EXISTS
    (SELECT * FROM employee e2 WHERE e2.SeniorID = e.EmpID

可能是使用JOIN的第三个,但我不熟悉SQL Server语法。

答案 4 :(得分:1)

一种解决方案是通过将“高级”关系拆分为单独的表来规范化。为了一般性,请将第二个表格设为“empID1 | empID2 | relationship_type”。

除此之外,您需要循环执行此操作。一种方法是:

declare @count int
select @count=count(1) from table
while (@count > 0)
BEGIN
    delete employee WHERE NOT EXISTS
       (select 1 from employee 'e_senior' 
        where employee.EmpID=e_senior.SeniorID)
    select @count=count(1) from table
END