Database 表的外键可以是同一表的复合主键的一部分吗?

Database 表的外键可以是同一表的复合主键的一部分吗?,database,database-design,data-modeling,Database,Database Design,Data Modeling,假设我有两个表:A(列为A、b、c、d)和b(列为x、y、z)。现在,(a,b)一起构成表a的主键,x是表b的主键。是否可以将b作为表a的外键,从表b中引用x 请尽快回复 提前感谢!:-) 是的,这没有问题。一个典型的示例(使用MySQL进行演示)是一个数据库表,其中包含多个公司,另一个包含可以为其中任何一个公司工作的员工: create table companies ( id int primary key, name varchar(20))

假设我有两个表:A(列为A、b、c、d)和b(列为x、y、z)。现在,
(a,b)
一起构成表a的主键,
x
是表b的主键。是否可以将
b
作为表a的外键,从表b中引用
x

请尽快回复


提前感谢!:-)

是的,这没有问题。一个典型的示例(使用MySQL进行演示)是一个数据库表,其中包含多个公司,另一个包含可以为其中任何一个公司工作的员工:

create table companies (
  id            int primary key,
  name          varchar(20));

create table employees (
  id            int,
  c_id          varchar(20) references companies(id),
  name          varchar(20),
  primary key   (id, c_id));

insert into companies (id, name) values (1, 'ABC');
insert into companies (id, name) values (2, 'DEF');
insert into companies (id, name) values (3, 'HIJ');

insert into employees (id, c_id, name) values (101, 1, "Allan");
insert into employees (id, c_id, name) values (102, 1, "Bobby");
insert into employees (id, c_id, name) values (101, 2, "Carol");
insert into employees (id, c_id, name) values (101, 3, "David");
请注意,
员工
的主键是由员工ID和公司ID组成的复合键。还请注意,公司ID是对
公司
主键的外键约束,即您询问的确切情况(功能上)

显示谁为哪家公司工作的查询显示了这一点:

select   c.id, c.name, e.id, e.name
from     companies c, employees e
where    c.id = e.c_id
order by c.id, e.id

c.id   c.name   e.id   e.name
----   ------   ----   ------        
   1   ABC       101   Allan
   1   ABC       102   Bobby
   2   DEF       101   Carol
   3   HIJ       101   David

复合主键中的列也可以是引用另一个表的主键的外键吗?当然可以。重要的问题是,这什么时候是个好主意

最常见的场景可能是交叉点或连接表。客户可以有多个地址(发货、账单等),并且地址可以有多个客户使用它们。因此,表CUSTOMER\u ADDRESSES有一个主键,该主键同时引用CUSTOMER和ADDRESS主键(对于奖励积分,ADDRESS\u类型也引用数据表)

我的示例使用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标识,其行由单调递增的数字标识。订单行表可能如下所示:

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)
     );  
请注意,我们可以将订单行建模为另一个交集表,主键为
(订单头id、产品id)
,并将
订单行编号
降级为普通属性的状态:这取决于我们必须表示的业务规则

第二种情况比你想象的要少见:复合主键在现实生活中非常罕见。例如,我认为中介绍的模型很弱。我们可能需要将员工用作许多关系(例如经理、任务、销售)的外键。使用复合键作为外键很笨拙(需要更多的输入!)。此外,当我们深入研究这些模型时,我们经常发现其中一个键列是自然键而不是主键,因此可能会发生更改。将更改级联到复合外键中的自然键列是一个PITN

因此,通常使用代理(或合成)主键,例如使用序列或标识列,并使用唯一约束强制自然键。后一步常常被遗忘,但它对于保持引用完整性至关重要。如果我们需要存储来自多家公司的员工的详细信息,包括公司的员工标识符,我们可能会有这样一个员工表:

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中,通常会发现级联到依赖表的复合主键。这里,复合键列构成了非规范化策略的一部分,以支持分区方案和/或有效的访问路径。

当然可以。你为什么不自己试试呢。写两个
CREATE TABLE
语句所需的时间与写那个问题所需的时间一样长。请不要使用像“尽快”这样的东西——这不是一个付费的支持平台。