【问题标题】:Insert 2 rows that are related in both directions in SQL在 SQL 中插入两个方向相关的 2 行
【发布时间】:2010-02-24 23:55:53
【问题描述】:

我有两张表是这样的:

// 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

【问题讨论】:

  • 永远不要使用@@identity。数据完整性非常糟糕的做法。您在 2008 年,因此请改用输出子句或 scope_identity(),。 @@identity 如果有人在您的表上放置了一个触发器,该触发器将插入到另一个具有标识列的表中,那么@@identity 将给出不正确的值,使用它是非常危险的。
  • +1 就我而言,我认为 SCOPE_IDENTITY() 将是最佳选择; OUTPUT 子句会略高于右上角吗?

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


【解决方案1】:

NULL 键将通过外键约束。您可以插入一个具有 NULL CreatorID 的 Person,这将成为整个层次结构的祖父。

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

【讨论】:

  • 我在 CreatorID 列上设置了 not null 这就是它不起作用的原因。感谢您的回答!
  • 你真的想要一个空创建者吗?如果这样不会违背专栏的目的吗?第二,人必须创造自己吗?
【解决方案2】:

不确定 SQL 服务器,但在我知道的其他 DBMS 中,只要这两个步骤在一个事务中,你就可以做到。只需将BEGIN;COMMIT; 之间的两个语句包装起来即可。

【讨论】:

    【解决方案3】:

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

    【讨论】:

    • 当我意识到我会遇到这个问题时,我也在想同样的事情。但是,我意识到这个问题与具有与经理的 EmployeeID PK 相关的 ManagerID FK 的员工表(在同一个表中)没有太大区别。如果您确实看到此设计可能引起的任何问题/并发症,如果您填写我将非常亲切。:-)
    【解决方案4】:

    模型在我看来有缺陷,但我认为您可能只需要更好地解释需求。到目前为止:

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

    是否有非员工的人员​​?为什么他们在系统中? Person 是否可以从 Employee 转换为不是 Employee,反之亦然?

    虽然我认为当您可以回答上述问题时可能会有更好的答案。一个建议是将 EmployeeCreaterId 更改为 PersonCreatorId,并有一个次要(不是通过数据库架构强制执行)要求 PersonCreatorId 是员工。

    【讨论】:

      【解决方案5】:

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

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

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2014-12-08
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-12-29
        • 1970-01-01
        • 1970-01-01
        • 2010-12-06
        相关资源
        最近更新 更多