在SQL中输入数据时处理循环引用

时间:2009-06-05 12:53:22

标签: sql

您使用什么样的sql技巧将数据输入到两个表中,其中包含循环引用。

Employees
    EmployeeID <PK>
    DepartmentID <FK> NOT NULL

Departments
    DepartmentID <PK>
    EmployeeID <FK> NOT NULL

员工属于某个部门,部门必须有经理(部门主管)。

我是否必须禁用插入的约束?

9 个答案:

答案 0 :(得分:13)

我假设您的Departments.EmployeeID是部门负责人。我要做的是让那个列可以为空;然后你可以先创建部门,然后创建员工。

答案 1 :(得分:5)

问:我是否必须禁用插件的约束?
答:在Oracle中,不,如果外键约束是DEFERRABLE,则不行(参见下面的示例)

对于Oracle:

    SET CONSTRAINTS ALL DEFERRED;
    INSERT INTO Departments values ('foo','dummy');
    INSERT INTO Employees values ('bar','foo');
    UPDATE Departments SET EmployeeID = 'bar' WHERE DepartmentID = 'foo';
    COMMIT;

让我们打开那个:

  • (自动提交必须关闭)
  • 推迟执行外键约束
  • 向Department表插入一行,其中FK列为“dummy”值
  • 使用FK引用部门
  • 向Employee表插入一行
  • 使用实际参考
  • 替换Department FK中的“dummy”值
  • 重新启用约束的执行

注意:禁用外键约束对所有会话生效,DEFERRING约束处于事务级别(如示例中)或会话级别(ALTER SESSION SET CONSTRAINTS=DEFERRED;

Oracle允许将外键约束定义为DEFERRABLE至少十年。我定义所有外键约束(当然)是可以直接推断的。这保持了所有人期望的默认行为,但允许操作而不需要禁用外键。

请参阅AskTom:http://www.oracle.com/technology/oramag/oracle/03-nov/o63asktom.html

见AskTom:http://asktom.oracle.com/pls/asktom/f?p=100:11:0::::P11_QUESTION_ID:10954765239682

另见:http://www.idevelopment.info/data/Oracle/DBA_tips/Database_Administration/DBA_12.shtml

[编辑]

答:在Microsoft SQL Server中,您不能像在Oracle中那样推迟外键约束。禁用和重新启用外键约束是一种方法,但我对1)性能影响(在重新启用约束时检查ENTIRE表的外键约束)的前景感到不寒而栗,2)处理异常如果(何时?)重新启用约束失败。请注意,禁用约束将影响所有会话,因此在禁用约束时,其他会话可能会插入和更新将导致约束重新启用失败的行。

使用SQL Server,更好的方法是删除NOT NULL约束,并在插入/更新行时允许NULL作为临时占位符。

对于SQL Server:

    -- (with NOT NULL constraint removed from Departments.EmployeeID)
    insert into Departments values ('foo',NULL)
    go
    insert into Employees values ('bar','foo')
    go
    update Departments set EmployeeID = 'bar' where DepartmentID = 'foo'
    go

[/编辑]

答案 2 :(得分:3)

这个问题可以用可取的约束来解决。提交整个事务时会检查此类约束,从而允许您在同一事务中插入员工和部门,并相互引用。 (假设数据模型有意义)

答案 3 :(得分:1)

通过删除循环引用来重构模式 从任一表模式中删除ID列。

在我看来,

Departments.EmployeeID 似乎不属于那里。

答案 4 :(得分:1)

我无法想到这样做的非hackish方式。我认为你需要删除约束或做一些在所有插入后更新的傻虚拟值。

我建议重构数据库架构。我想不出你为什么要这样工作的原因。

也许像Employee,EmployeeDepartment(EmployeeId,DepartmentId)和Department这样可以更好地实现同样的目标。

答案 5 :(得分:1)

你可以在Department表中为'Unassigned'

创建一行

要使用新员工创建新部门,您可以

  1. 在“未分配”部门中创建员工(EmployeeA)
  2. 使用员工EmployeeA
  3. 创建新部门(DepartmentA)
  4. 将EmployeeA更新为DepartmentA
  5. 这不会使您当前的架构失效,您可以设置一个定期运行的任务,以检查是否没有未分配部门的成员。

    您还需要创建一个默认员工作为未分配的员工

    编辑:

    混乱提出的解决方案虽然简单得多,但

答案 6 :(得分:1)

我使用过一些好的设计。所有这些都涉及从Department表中删除“manager”EmployeeID并从Employee表中删除DepartmentID。我已经看到了几个提到它的答案,但我会澄清我们如何使用它:

我通常最终得到一个EmployeeDepartment关系链表 - 多对多,通常带有IsManager,IsPrimaryManager,IsAdmin,IsBackupManager等标志,它们澄清了一些可能受到限制的关系,因此每个只允许一个主管理器部门(虽然一个人可以是多个部门的PrimaryManager)。如果您不喜欢单个表,那么您可以拥有多个表:EmployeeDepartment,ManagerDepartment等,但是您可能会遇到一个人是经理但不是员工的情况等。

我们通常也允许人们成为多个部门的成员。

为简化访问,您可以提供适当执行连接的视图。

答案 7 :(得分:0)

是的,在这种情况下,您必须禁用外键。

答案 8 :(得分:0)

您需要永久删除一个或另一个参考。这不是一个可行的设计结构。哪个必须先进入?部门还是员工?除非你的部门都是一个大员工,否则结构就没有意义,因为每个员工都必须有明显的离职。