-
外键必须是另一个表的主键吗?
答:
不一定是主键,但必须是唯一性索引。
-
FOREIGN KEY 约束
外键 (FK) 是用于建立和加强两个表数据之间的链接的一列或多列。当创建或修改表时可通过定义 FOREIGN KEY 约束来创建外键。
在外键引用中,当一个表的列被引用作为另一个表的主键值的列时,就在两表之间创建了链接。这个列就成为第二个表的外键。
例如,因为销售订单和销售人员之间存在一种逻辑关系,所以 AdventureWorks 数据库中的 Sales.SalesOrderHeader 表含有一个指向Sales.SalesPerson 表的链接。SalesOrderHeader 表中的 SalesPersonID 列与 SalesPerson 表中的主键列相对应。SalesOrderHeader 表中的SalesPersonID 列是指向 SalesPerson 表的外键。
FOREIGN KEY 约束并不仅仅可以与另一表的 PRIMARY KEY 约束相链接,它还可以定义为引用另一表的 UNIQUE 约束。FOREIGN KEY 约束可以包含空值,但是,如果任何组合 FOREIGN KEY 约束的列包含空值,则将跳过组成 FOREIGN KEY 约束的所有值的验证。若要确保验证了组合 FOREIGN KEY 约束的所有值,请将所有参与列指定为 NOT NULL。
-
什么是主键、外键:
关系型数据库中的一条记录中有若干个属性,若其中某一个属性组(注意是组)能唯一标识一条记录,该属性组就可以成为一个主键
比如
学生表(学号,姓名,性别,班级)
其中每个学生的学号是唯一的,学号就是一个主键
课程表(课程编号,课程名,学分)
其中课程编号是唯一的,课程编号就是一个主键
成绩表(学号,课程号,成绩)
成绩表中单一一个属性无法唯一标识一条记录,学号和课程号的组合才可以唯一标识一条记录,所以 学号和课程号的属性组是一个主键
成绩表中的学号不是成绩表的主键,但它和学生表中的学号相对应,并且学生表中的学号是学生表的主键,则称成绩表中的学号是学生表的外键
同理 成绩表中的课程号是课程表的外键
定义主键和外键主要是为了维护关系数据库的完整性,总结一下:
1.主键是能确定一条记录的唯一标识,比如,一条记录包括身份正号,姓名,年龄。
身份证号是唯一能确定你这个人的,其他都可能有重复,所以,身份证号是主键。
2.外键用于与另一张表的关联。是能确定另一张表记录的字段,用于保持数据的一致性。
比如,A表中的一个字段,是B表的主键,那他就可以是A表的外键。
-
主键、外键和索引的区别
| 主键 | 外键 | 索引 |
定义: | 唯一标识一条记录,不能有重复的,不允许为空 | 表的外键是另一表的主键, 外键可以有重复的, 可以是空值 | 该字段没有重复值,但可以有一个空值 |
作用: | 用来保证数据完整性 | 用来和其他表建立联系用的 | 是提高查询排序的速度 |
个数: | 主键只能有一个 | 一个表可以有多个外键 | 一个表可以有多个惟一索引 |
聚集索引和非聚集索引的区别?
聚集索引一定是唯一索引。但唯一索引不一定是聚集索引。
聚集索引,在索引页里直接存放数据,而非聚集索引在索引页里存放的是索引,这些索引指向专门的数据页的数据。
-
数据库中主键和外键的设计原则
主键和外键是把多个表组织为一个有效的关系数据库的粘合剂。主键和外键的设计对物理数据库的性能和可用性都有着决定性的影响。
必须将数据库模式从理论上的逻辑设计转换为实际的物理设计。而主键和外键的结构是这个设计过程的症结所在。一旦将所设计的数据库用于了生产环境,就很难对这些键进行修改,所以在开发阶段就设计好主键和外键就是非常必要和值得的。
主键:
关系数据库依赖于主键---它是数据库物理模式的基石。
主键在物理层面上只有两个用途:
1. 惟一地标识一行。
2. 作为一个可以被外键有效引用的对象。
基于以上这两个用途,下面给出了我在设计物理层面的主键时所遵循的一些原则:
1. 主键应当是对用户没有意义的。如果用户看到了一个表示多对多关系的连接表中的数据,并抱怨它没有什么用处,那就证明它的主键设计地很好。
2. 主键应该是单列的,以便提高连接和筛选操作的效率。
注:使用复合键的人通常有两个理由为自己开脱,而这两个理由都是错误的。其一是主键应当具有实际意义,然而,让主键具有意义只不过是给人为地破坏数据库提供了方便。其二是利用这种方法可以在描述多对多关系的连接表中使用两个外部键来作为主键,我也反对这种做法,理由是:复合主键常常导致不良的外键,即当连接表成为另一个从表的主表,而依据上面的第二种方法成为这个表主键的一部分,然,这个表又有可能再成为其它从表的主表,其主键又有可能成了其它从表主键的一部分,如此传递下去,越靠后的从表,其主键将会包含越多的列了。
3. 永远也不要更新主键。实际上,因为主键除了惟一地标识一行之外,再没有其他的用途了,所以也就没有理由去对它更新。如果主键需要更新,则说明主键应对用户无意义的原则被违反了。
注:这项原则对于那些经常需要在数据转换或多数据库合并时进行数据整理的数据并不适用。
4. 主键不应包含动态变化的数据,如时间戳、创建时间列、修改时间列等。
5. 主键应当有计算机自动生成。如果由人来对主键的创建进行干预,就会使它带有除了惟一标识一行以外的意义。一旦越过这个界限,就可能产生认为修改主键的动机,这样,这种系统用来链接记录行、管理记录行的关键手段就会落入不了解数据库设计的人的手中。
-
外键约束的三种情况:
因为外键和被引用的主键(唯一键)之间构成一种的主从关系;
被引用的表是主表,存在外键的表是从表;
当主表中的被引用为外键的数据记录被删除时,会影响从表中的记录(因为从表使用了主表的字段作为了外键)
产生三种主从表的处理情况:
默认的; 不允许主表删除被从表引用为外键的记录;
set null;主表可以删除记录,然后从表把外键字段的值设置为null,
cascade;主表可以删除记录,同时也删除从表中引用该记录作为外键的所有的记录;
-----------外键约束的三种情况-------------------
--------------------------------------------------------------------------------
--1. 默认的; 不允许主表删除被从表引用为外键的记录;
--------------------------------------------------------------------------------
-- 主表,部门表
create table dept10(dept_id,dept_name,manager_id,location_id)
as select d.department_id,d.department_name,d.manager_id,d.location_id from departments d;
-- 添加主键约束
alter table dept10 add constraint dept10_deptId_pk primary key(dept_id);
-- 从表,员工表
create table emps10 (
emp_id number(11) not null,
emp_name nvarchar2(50),
manager_id number(11),
dept_id number(11),
--- 表级约束
constraint emps10_empId_pk primary key(emp_id),
constraint emps10_deptId_fk foreign key(dept_id)
references dept10(dept_id) -- 外键的默认约束
);
--- 插入数据
insert into emps10(emp_id,emp_name,manager_id,dept_id)
select e.employee_id,e.first_name || ' '||e.last_name,e.manager_id,e.department_id
from employees e where e.department_id in (select dept_id from dept10);
-- 提交事务
commit;
--- 不允许删除主表中作为外键的记录
delete from dept10 where dept_id = 60;
--------------------------------------------------------------------------------
--2. set null;主表可以删除记录,然后从表把外键字段的值设置为null
--------------------------------------------------------------------------------
-- 主表,部门表
create table dept20(dept_id,dept_name,manager_id,location_id)
as select d.department_id,d.department_name,d.manager_id,d.location_id from departments d;
-- 添加主键约束
alter table dept20 add constraint dept20_deptId_pk primary key(dept_id);
-- 从表,员工表
create table emps20 (
emp_id number(11) not null,
emp_name nvarchar2(50),
manager_id number(11),
dept_id number(11),
--- 表级约束
constraint emps20_empId_pk primary key(emp_id),
constraint emps20_deptId_fk foreign key(dept_id)
references dept20(dept_id) on delete set null -- 外键的set null约束
);
--- 插入数据
insert into emps20(emp_id,emp_name,manager_id,dept_id)
select e.employee_id,e.first_name || ' '||e.last_name,e.manager_id,e.department_id
from employees e where e.department_id in (select dept_id from dept20);
-- 提交事务
commit;
--- 查询数据
select * from dept20;
select * from emps20;
--- 删除主表中作为外键的记录,从表中的外键会设置为null值
delete from dept20 where dept_id = 60;
-----------------------------------------------------------------------------------
--3. cascade;主表可以删除记录,同时也删除从表中引用该记录作为外键的所有的记录;
----------------------------------------------------------------------------------
-- 主表,部门表
create table dept30(dept_id,dept_name,manager_id,location_id)
as select d.department_id,d.department_name,d.manager_id,d.location_id from departments d;
-- 添加主键约束
alter table dept30 add constraint dept30_deptId_pk primary key(dept_id);
-- 从表,员工表
create table emps30 (
emp_id number(11) not null,
emp_name nvarchar2(50),
manager_id number(11),
dept_id number(11),
--- 表级约束
constraint emps30_empId_pk primary key(emp_id),
constraint emps30_deptId_fk foreign key(dept_id)
references dept30(dept_id) on delete cascade -- 外键的cascade约束
);
--- 插入数据
insert into emps30(emp_id,emp_name,manager_id,dept_id)
select e.employee_id,e.first_name || ' '||e.last_name,e.manager_id,e.department_id
from employees e where e.department_id in (select dept_id from dept30);
-- 提交事务
commit;
--- 查询数据
select * from dept30;
select * from emps30;
--- 删除主表中作为外键的记录,从表中的外键会设置为null值
delete from dept30 where dept_id = 60;
------------------------------------------------------------------------------------
-----------外键约束的三种情况-------------------
参考1:https://blog.csdn.net/haiross/article/details/50435374
参考2:https://blog.csdn.net/bingqingsuimeng/article/details/51595560