如何在SQL Server中创建外键?

260

我从未手写过用于 SQL Server 的对象创建代码,而且在 SQL Server 和 Postgres 之间,外键声明似乎有所不同。以下是迄今为止我的 SQL 代码:

drop table exams;
drop table question_bank;
drop table anwser_bank;

create table exams
(
    exam_id uniqueidentifier primary key,
    exam_name varchar(50),
);
create table question_bank
(
    question_id uniqueidentifier primary key,
    question_exam_id uniqueidentifier not null,
    question_text varchar(1024) not null,
    question_point_value decimal,
    constraint question_exam_id foreign key references exams(exam_id)
);
create table anwser_bank
(
    anwser_id           uniqueidentifier primary key,
    anwser_question_id  uniqueidentifier,
    anwser_text         varchar(1024),
    anwser_is_correct   bit
);

运行查询时出现以下错误:

Msg 8139, Level 16, State 0, Line 9 外键中引用列数量与被引用表“question_bank”的列数量不一致。

您能发现错误吗?


2
FYI,在使用ORM时,最好总是为您的约束命名。 - Tracker1
11个回答

345

如果你只想单独创建约束,可以使用 ALTER TABLE

alter table MyTable
add constraint MyTable_MyColumn_FK FOREIGN KEY ( MyColumn ) references MyOtherTable(PKColumn)

我不建议使用Sara Chipps提到的内联创建语法,因为我更愿意命名自己的约束条件。


19
我知道这个问题很旧了,但我通过谷歌搜索到这里,还有许多其他人也可能会搜索到。只需要快速修复一下:正确的引用方式是:REFERENCES MyOtherTable(MyOtherIDColumn)。 - PedroC88
4
"MyTable_MyColumn_FK" 是最佳的命名实践。 - Shaiju T

209
create table question_bank
(
    question_id uniqueidentifier primary key,
    question_exam_id uniqueidentifier not null,
    question_text varchar(1024) not null,
    question_point_value decimal,
    constraint fk_questionbank_exams foreign key (question_exam_id) references exams (exam_id)
);

37
给外键约束命名也是有帮助的。这有助于解决外键违规问题。例如:"外键 fk_questionbank_exams ( question_exam_id ) 引用 exams (exam_id)" - John Vasileff
31
我同意命名约束是一个好计划,但至少在 SQL Server 2008 R2 中,最后一行的语法必须是“constraint fk_questionbank_exams foreign key (question_exam_id) references exams (exam_id)”。 - Jonathan Sayce
6
需要注意的一个非常重要的点是,创建外键并不会创建索引。将另一张表与此表连接可能会导致查询非常缓慢。 - Rocklan
我不确定为什么会有所不同,但我必须执行 CONSTRAINT fk_questionbank_exams FOREIGN KEY (question_exam_id) REFERENCES exams (exam_id)。 - tenmiles
在编写主键约束时,是否需要为主键编写非空(NON NULL)约束?例如,仅将列指定为主键是否足以表示该列具有非空约束,还是必须显式地指定 NON NULL 约束? - gary

71

你也可以使用以下方法为外键约束命名:

CONSTRAINT your_name_here FOREIGN KEY (question_exam_id) REFERENCES EXAMS (exam_id)

1
在使用ORM时,拥有对外键表的多个引用的命名约束非常有帮助...在EF4中,在属性中使用命名约束,这样我就知道哪个联系人表条目是为买方、卖方等而设的。 - Tracker1

33

我喜欢AlexCuse的答案,但是在添加外键约束时你需要注意的一点是如何处理引用表中行的参考列的更新,尤其是当你想要删除引用表中的行时应该怎么处理。

如果像这样创建了一个约束:

alter table MyTable
add constraint MyTable_MyColumn_FK FOREIGN KEY ( MyColumn ) 
references MyOtherTable(PKColumn)

如果在引用表中存在对应的行,则在被引用的表中进行更新或删除操作将会导致错误。

尽管这可能是你想要的行为,但根据我的经验,通常情况下并非如此。

如果你采用以下方式创建:

alter table MyTable
add constraint MyTable_MyColumn_FK FOREIGN KEY ( MyColumn ) 
references MyOtherTable(PKColumn)
on update cascade 
on delete cascade

那么,在父表中进行更新和删除将导致引用表中相应行的更新和删除。

(我并不建议改变默认设置,因为默认会偏向于谨慎,这是好的。我只是在说,创建约束时应该始终注意这一点。)

顺便说一下,可以在创建表时像这样完成:

create table ProductCategories (
  Id           int identity primary key,
  ProductId    int references Products(Id)
               on update cascade on delete cascade
  CategoryId   int references Categories(Id) 
               on update cascade on delete cascade
)

使用“alter table MyTable (...)”更好。 :) - Sylvain Rodrigue

15
create table question_bank
(
    question_id uniqueidentifier primary key,
    question_exam_id uniqueidentifier not null constraint fk_exam_id foreign key references exams(exam_id),
    question_text varchar(1024) not null,
    question_point_value decimal
);

--那也可以。也许更直观的结构?


1
这是我的做法,但我有一个问题,添加“外键”关键字有什么意义吗?似乎没有那个也可以工作,例如:question_exam_id uniqueidentifier not null references exams(exam_id)。 - JSideris
“Foreign key”关键字是可选的。在我看来,这使得代码更易读。 - Bijimon

8
如果想通过查询将两个表的列建立关系,请尝试以下方法:
Alter table Foreign_Key_Table_name add constraint 
Foreign_Key_Table_name_Columnname_FK
Foreign Key (Column_name) references 
Another_Table_name(Another_Table_Column_name)

8
在任何表上创建外键:
ALTER TABLE [SCHEMA].[TABLENAME] ADD FOREIGN KEY (COLUMNNAME) REFERENCES [TABLENAME](COLUMNNAME)
EXAMPLE
ALTER TABLE [dbo].[UserMaster] ADD FOREIGN KEY (City_Id) REFERENCES [dbo].[CityMaster](City_Id)

5

和你一样,我通常不会手动创建外键,但如果出于某种原因我需要脚本这样做,我通常使用ms sql server管理工具进行创建。在保存更改之前,我选择“表设计器|生成更改脚本”。


5

这个脚本是关于使用外键创建表格,我添加了参照完整性约束sql-server

create table exams
(  
    exam_id int primary key,
    exam_name varchar(50),
);

create table question_bank 
(
    question_id int primary key,
    question_exam_id int not null,
    question_text varchar(1024) not null,
    question_point_value decimal,
    constraint question_exam_id_fk
       foreign key references exams(exam_id)
               ON DELETE CASCADE
);

4

我总是使用这个语法在两个表之间创建外键约束:

Original Answer翻译成:"最初的回答"

Alter Table ForeignKeyTable
Add constraint `ForeignKeyTable_ForeignKeyColumn_FK`
`Foreign key (ForeignKeyColumn)` references `PrimaryKeyTable (PrimaryKeyColumn)`

最初的回答
即,例如。
Alter Table tblEmployee
Add constraint tblEmployee_DepartmentID_FK
foreign key (DepartmentID) references tblDepartment (ID)

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接