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はおそらくnullを許可するため、関係が存在する必要はありませんが、その列に値を入れようとすると、SQL ServerはFKが有効であることを確認します。そうでない場合、エラーが発生します。

于 2011-03-26T13:50:15.040 に答える
0

mssqlサーバーの自己参照キーのこの例を作成しました

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 に答える