外键关系问题

时间:2015-09-06 17:40:21

标签: database-design foreign-keys entity-relationship

我有以下架构:

公司

id (PK)
name 

用户

id (PK)
name
dept_id (FK) // references id on Depts table

科指南

id (PK)
name
manager_id (FK) // references id on Users table
company_id (FK) // references id on companies table

事实:

  • 部门属于公司
  • 部门由用户管理
  • 用户属于部门
  • 用户可以管理多个部门

当两个表都需要来自另一个表的外键时,如何创建用户记录或部门记录?

如果我有一个部门,它必须有一个经理,但如果我有一个用户,他们必须被分配到一个部门。例如,如果我首先尝试创建用户,则FK dept_id约束会失败,因为不存在Dept。如果我首先尝试创建Dept,则FK manager_id约束会失败,因为没有用户。

***更新****

如果引入了一些映射表,如果父表使用唯一的id号作为主键,为什么我需要这么多复合主键和外键。

create table companies (
  id integer auto_inc primary key,
  company_name varchar(50) not null
);

create table departments (
  id integer auto_inc primary key
  company_id integer not null references id on companies
  dept_name varchar(50) not null
);

create table employees (
  id integer auto_inc primary key, 
  company_id integer not null references id on companies,
  emp_name varchar(50) not null,
  emp_num integer
);

create table managed_departments (
  company_id integer not null, 
  dept_id integer not null, 
  manager_id integer not null, 
  foreign key (company_id, dept_id) references departments,
  foreign key (manager_id) references employees (id),
  primary key (company_id, dept_id)
);

create table department_staff (
  company_id integer not null, 
  dept_id integer not null, 
  emp_id integer not null, 
  foreign key (company_id, dept_id) references managed_departments,
  foreign key (emp_id) references employees (id),
  primary key (company_id, dept_id, emp_id)
); 

*更新*

Schema翻译成Laravel

 Schema::create('companies', function (Blueprint $table) {
        $table->increments('id');
        $table->string('name')->unique();
        $table->timestamps();
 });

 Schema::create('departments', function (Blueprint $table) {
        $table->increments('id');
        $table->integer('company_id');
        $table->string('name');
        $table->timestamps();

        $table->foreign('company_id')->references('id')->on('companies');
        $table->unique(['company_id','name']);
}); 

Schema::create('employees', function (Blueprint $table) {
        $table->increments('id');
        $table->integer('company_id');
        $table->string('name');
        $table->timestamps();

         $table->foreign('company_id')->references('id')->on('companies');
 });


  Schema::create('managed_departments', function (Blueprint $table) {
        $table->integer('company_id');
        $table->integer('department_id');
        $table->integer('manager_id');
        $table->timestamps();

        $table->primary(['company_id','department_id']);

        $table->foreign(['company_id','department_id'])
              ->references(['company_id','department_id'])
              ->on('departments');

        $table->foreign(['company_id','manager_id'])
              ->references(['company_id','id'])
              ->on('employees');
 });

 Schema::create('department_staff', function (Blueprint $table) {
        $table->integer('company_id');
        $table->integer('department_id');
        $table->integer('employee_id');
        $table->timestamps();

        $table->primary(['company_id','department_id', 'employee_id']);

        $table->foreign(['company_id','department_id'])
              ->references(['company_id','department_id'])
              ->on('managed_departments');

        $table->foreign(['company_id','employee_id'])
              ->references(['company_id','id'])
              ->on('employees');
 });

1 个答案:

答案 0 :(得分:1)

当你发现自己被绑在这样的结上时,你通常需要更多的桌子。

公司很容易。为了便于阅读,我几乎完全省略了id号。

create table companies (
  company_name varchar(45) primary key
);

insert into companies values
('Vandelay, Inc'), ('Vertigenous, Inc');

将“部门”视为组织结构图中的部门。这不是全部故事。

create table departments (
  company_name varchar(45) not null references companies,
  dept_name varchar(30) not null,
  primary key (company_name, dept_name)
);

insert into departments values
('Vandelay, Inc', 'Human resources'), 
('Vertigenous, Inc', 'Personnel'),
('Vandelay, Inc', 'Information Technology'), 
('Vertigenous, Inc', 'Information Systems');

公司需要一些员工。员工获得一个身份证号码,因为他们的名字在公司内部不一定是唯一的。

create table employees (
  company_name varchar(45) not null references companies,
  emp_id integer not null,
  emp_name varchar(25) not null,
  primary key (company_name, emp_id)
);

insert into employees values
('Vandelay, Inc', 1, 'Steven McGuire'), 
('Vertigenous, Inc', 1, 'Michael McDonald'),
('Vandelay, Inc', 2, 'Rosalie Jimenez'),
('Vandelay, Inc', 3, 'Phil Roberson'),
('Vandelay, Inc', 4, 'Sylvester Davis');

现实世界中的部门(即组织结构图上的部门)有一名经理。重叠的外键约束保证了经理和部门属于同一家公司。

-- Assumes one current manager per department.
create table managed_departments (
  company_name varchar(45) not null,
  dept_name varchar(30) not null,
  foreign key (company_name, dept_name) references departments,
  manager_id integer not null,
  foreign key (company_name, manager_id) references employees (company_name, emp_id),
  primary key (company_name, dept_name)
);

insert into managed_departments values
('Vandelay, Inc', 'Human resources', 1),
('Vertigenous, Inc', 'Personnel', 1),
('Vandelay, Inc', 'Information Technology', 2);

要完成工作,请将员工分配到某个部门。同样,重叠的外键实现了业务需求 - 员工和管理的部门属于同一家公司。

create table department_staff (
  company_name varchar(45) not null,
  dept_name varchar(30) not null,
  foreign key (company_name, dept_name) references managed_departments,
  emp_id integer not null,
  foreign key (company_name, emp_id) references employees,
  primary key (company_name, dept_name, emp_id)
);


insert into department_staff values
('Vandelay, Inc', 'Human resources', 1),
('Vandelay, Inc', 'Information Technology', 2),
('Vandelay, Inc', 'Information Technology', 3),
('Vandelay, Inc', 'Information Technology', 4);

这允许员工“进入”多个部门,这在我的经验中实际上很常见。如果您希望每个员工只在一个部门“进入”,请为DDL添加一个约束“department_staff”。

unique (company_name, emp_id)