复合主键中的列也可以是引用另一个表的主键的外键吗?当然可以。重要的问题是,什么时候这是个好主意?
最常见的场景可能是交叉口或交汇点表。客户可以有多个地址(运输、账单等),并且地址可以有多个客户使用它们。因此,表 CUSTOMER_ADDRESSES 有一个主键,它同时引用了 CUSTOMER 和 ADDRESS 主键(对于奖励点,ADDRESS_TYPE 也引用数据表)。
我的示例使用 Oracle 12c 语法:
create table customer_address
( customer_id number(38,0) not null
, address_id number(38,0) not null
, address_type_code varchar2(3) not null
, constraint customer_address_pk primary key
(customer_id, address_id, address_type_code)
, constraint customer_address_customer_fk foreign key
(customer_id) references customer(customer_id)
, constraint customer_address_address_fk foreign key
(address_id) references address(address_id)
, constraint customer_address_type_fk foreign key
(address_type_code) references address_type(address_type_code)
);
当子表的主键由父键和仅在父键中唯一的标识符(通常是数字)组成时,会发生第二种情况。例如,一个订单有一个订单标题和一些订单行。订单由订单标题 ID 标识,其行由单调递增的数字标识。 ORDER_LINE 表可能如下所示:
create table order_line
( order_header_id number(38,0) not null
, order_line_no number(38,0) not null
, product_id number(38,0) not null
, qty number(38,0) not null
, constraint order_line_pk primary key
(order_header_id, order_line_no)
, constraint order_line_header_fk foreign key
(order_header_id) references order_header(order_header_id)
, constraint order_line_product_fk foreign key
(product_id) references product(product_id)
);
请注意,我们可以将 ORDER_LINE 建模为另一个交集表,主键为(order_header_id, product_id),并将order_line_no 降级为普通属性状态:这取决于我们必须表示的业务规则。
第二种情况比您想象的要少:复合主键在现实生活中非常少见。例如,我认为that other answer 中提出的模型很弱。我们可能需要将 Employee 用作许多关系(例如 Manager、Assignment、Sales)的外键。为外键使用复合键很笨拙(更多输入!)。此外,当我们深入研究这些模型时,我们经常发现其中一个键列是自然键而不是主键,因此可能会发生变化。对复合外键中的自然键列的级联更改是 PITN。
因此,通常的做法是使用代理(或合成)主键,例如使用序列或标识列,并使用唯一约束强制自然键。后一步经常被遗忘,但它对于保持参照完整性至关重要。假设我们需要存储来自多个公司的员工的详细信息,包括公司的员工标识符,我们可能会有一个像这样的 EMPLOYEE 表:
create table employee
( employee_id number(38,0) generated always as number
, company_id number(38,0) not null
, company_employee_id varchar2(128) not null
, name varchar2(128) not null
, constraint employee_pk primary key
(employee_id)
, constraint employee_uk unique
(company_id, company_employee_id)
, constraint employee_company_fk foreign key
(company_id) references company(company_id)
);
在数据仓库和其他 VLDB 中发现级联到依赖表的复合主键很常见的一种情况。在这里,复合键列构成了非规范化策略的一部分,以支持分区方案和/或有效的访问路径。