11
create table EMP(Eid int primary key)

insert into EMP values(11e3)

--自引用

alter table EMP 
add constraint fk_EMP_Eid 
foreign key (Eid) references EMP(Eid)

--现在插入

insert into EMP values(12e2)

但是,这个插入应该失败,因为 EMP 表中没有先前的值Eid=1200,所以当外键将引用该列时,它不会找到该值,因此插入应该失败。

但为什么会成功?

4

3 回答 3

12

该列引用自身。

因此,添加行本身可以保证存在匹配的行。这种约束永远不会失败。

事实上,查看执行计划 SQL Server 意识到了这一点,甚至懒得检查它。没有assert操作员在场。

计划

如果我们创建一个更典型的 Employee 表,那么对于可能违反约束的插入有不同的计划,如下所示。

create table EMP2(Eid int primary key, boss_id int null);
alter table EMP2 add constraint fk_EMP2_Eid 
 foreign key (boss_id) references EMP2(Eid)

insert into EMP2 values(1,null) /*Can't violate constraint as NULL*/
insert into EMP2 values(2,1)    /*Can violate constraint as NOT NULL*/

计划

如果您尝试多行,则会将阻塞线轴添加到计划中,因此在插入所有行之前不会检查约束。

insert into EMP2 values (3,2),(4,3) /*Can violate constraint - multiple rows*/

计划

并且只是为了完整起见,正如评论中提出的那样,查看插入到具有 FK 引用不同表的表的情况......

CREATE TABLE EmpSalaryHistory
(
Eid INT NOT NULL REFERENCES EMP(Eid),
EffectiveDate DATETIME NOT NULL,
Salary INT,
PRIMARY KEY (Eid,EffectiveDate)
)

INSERT INTO EmpSalaryHistory
VALUES    (1,GETDATE(),50000),
          (2,GETDATE(),50000)

在这种情况下,不会将线轴添加到计划中,因为它插入每一行而不是最后插入所有行,因此它可以在行失败时更早回滚(最终结果将相同)

计划

于 2011-03-26T13:50:17.113 回答
0

您的 FK 列 fk_EMP_Eid 可能允许空值,因此不需要存在该关系,但如果您尝试在该列中放置一个值,则 SQL Server 将验证 FK 是否有效,否则它将出错。

于 2011-03-26T13:50:15.040 回答
0

我为 ms sql server 的自引用键创建了这个示例

CREATE TABLE Category (
   CategoryId int IDENTITY(1,1) not null,
   ParentId int null,
   CONSTRAINT PK_CategoryId PRIMARY KEY CLUSTERED (CategoryId),
   CONSTRAINT FK_ParentId FOREIGN KEY (ParentId) REFERENCES  Category(CategoryId),
   Title nvarchar(255) NOT NULL
);

insert into category(title)
values
('category1');

insert into category(title,parentid)
values
('category2',1);
于 2020-02-29T07:46:20.303 回答