在SQL中插入两个方向相关的行

时间:2010-02-24 23:55:53

标签: sql sql-server sql-server-2008 insert relational

我有两张桌子:

// Person.Details Table:
PersonID int [PK] | EmployeeCreatorID int [FK] | FirstName varchar | OtherInfo...

// Employee.Details Table:
EmployeeID int [PK] | PersonID int [FK] | IsAdmin bit | OtherInfo...

每个表都与另一个表相关:

[Employee.Details.PersonID]===>[Person.Details.PersonID] AND
[Person.Details.EmployeeCreatorID]===>[Employee.Details.EmployeeID]

通过他们的外键。

问题是,如果不删除其中一个外键约束,插入行,然后再添加约束(这是非常蹩脚的),就无法创建第一个人/员工。

这里显而易见的上帝悖论是第一个“员工”不存在来创造自己(“人”)。

有没有办法同时将数据插入两个表?这个创建的创建者场景只需要发生一次。如果我不能同时将数据插入两个表中,那么你还有其他任何方法吗?

澄清

还有其他与“人物”表相关的表格......如“学生”和“监护人”。一个人不能切换类型(员工不能切换到学生或监护人,反之亦然)。矛盾类似于具有ManagerID FK的Employee表;除了我的情况,表格已经分开了。

感谢Remus Rusanu和b0fh

--/*seeds database with first employee*/
BEGIN TRAN
GO
INSERT INTO Person.Details
    (EmployeeCreatorID, FirstName, Active)
VALUES
    (@@Identity, 'Admin', 1)
DECLARE @Identity int;
SET @Identity = @@Identity;
INSERT INTO Employee.Details 
    (PersonID, IsAdmin, Email, Password) 
VALUES
    (@Identity, 1, 'admin', 'admin')
UDPATE
    Person.Details
SET
    EmployeeCreatorID = @@Identity
WHERE
    PersonID = @Identity

IF(@@ERROR <> 0)
    ROLLBACK TRAN
ELSE
    COMMIT TRAN

5 个答案:

答案 0 :(得分:3)

NULL键将传递外键约束。你可以插入一个具有NULL CreatorID的Person,这将成为整个层次结构的大爸爸。

您还可以插入禁用约束,插入指向彼此的第一对(Person,Employee),然后启用约束,从现在开始系统播种。

答案 1 :(得分:2)

不确定SQL服务器,但在我知道的其他DBMS中,只要这两个步骤在单个事务中,就可以执行。只需在BEGIN;COMMIT;之间包含两个语句。

答案 2 :(得分:1)

我宁愿改变数据库设计。表格不应该以这种方式相关联。

答案 3 :(得分:0)

模型对我来说是有缺陷的,但我认为你可能只需要更好地解释这些要求。到目前为止:

  • 每个人都是由员工创建的。
  • 员工是个人。

是否有员工不是员工?他们为什么在系统中?一个人是否有可能从员工转为非员工,反之亦然?

虽然我认为当你可以回答上述问题时可能会有更好的答案。一个建议就是将EmployeeCreaterId更改为PersonCreatorId,并且具有PersonCreatorId是雇员的辅助(不强制通过数据库模式)要求。

答案 4 :(得分:0)

您只需要有一名员工来创建可能是或可能不是员工的人员​​。唯一的问题是员工无法创造自己。所以我建议在进入数据库的第一个人之前确保employeecreatorid fk不是必需的列。 然后创建这个人。 然后为该相关人员创建员工记录。由于您有一个人,您可以在employee表中要求personID FK并且它将存在。 然后更新原始Person记录设置EmployeeCreatorId等于新创建的EmployeeID 接下来,将person表中的EmployeeCreatorID FK列设置回所需的值 现在,您必须确保只有当前员工创建任何新员工,而当前员工不会是正在创建的人员。

这将避免每次创建新人时都需要删除和重新创建密钥。祝你好运。