外键关系问题

Foreign key relationship issue

我有以下架构:

公司

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

事实:

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

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

*** 已更新 ****

如果引入了一些映射 table,如果父 table 使用唯一 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)
); 

* 更新 *

架构翻译成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');
 });

当你发现自己陷入这样的困境时,你通常需要更多的桌子。

公司是比较容易的部分。为了便于阅读,我几乎完全省略了 ID 号。

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

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

将此处的 "departments" 视为组织结构图上的部门。这不是全部。

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');

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

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);

这让一名员工可以 "in" 多个部门,这在我的经验中其实很常见。如果您希望每位员工 "in" 只有一个部门,请向 "department_staff".

的 DDL 添加约束
unique (company_name, emp_id)