簡體   English   中英

在 postgres 中強制執行子集關系

[英]Enforce subset relationship in postgres

如何在不使用應用程序代碼的情況下在我的數據庫模式中強制執行以下業務邏輯:

  • 一個用戶必須屬於一個公司
  • 一個公司可以有多輛車
  • 一輛車可以有多家公司
  • 用戶可以擁有多輛車,但這些車輛必須是鏈接到用戶公司的車輛的子集(即用戶不能鏈接到其公司無權訪問的車輛)

這是我到目前為止所擁有的:

create table companies (
    id serial primary key,
    name varchar not null,
    unique(name)
);

create table vehicles (
    id serial primary key,
    name varchar not null,
    unique(name)
);

create table users (
    id serial primary key,
    company_id integer not null,
    name varchar not null,
    foreign key (company_id) references companies(id)
);

create table vehicle_companies (
    id serial primary key,
    vehicle_id integer not null,
    company_id integer not null,
    foreign key (vehicle_id) references vehicles(id),
    foreign key (company_id) references companies(id)
);

create table user_vehicles (
    user_id integer not null,
    vehicle_company_id integer not null,
    foreign key (user_id) references users(id),
    foreign key (vehicle_company_id) references vehicle_companies(id)
);

我怎樣才能確保user_vehicles表中的行始終只引用具有company_idvehicle_companies記錄,這與其引用的users表記錄的company_id相同?

我正在使用 postgres。

您正在嘗試跨獨立實體(表)實施參照完整性。 你不能用簡單的約束來做到這一點(也許是排除約束——但我不這么認為)。 為此,您需要在user_vehicles上觸發。

create or replace function validate_user_vehicle_company() 
    returns trigger 
   language plpgsql
as $$
begin 
    if not exists( select null 
                     from users u 
                     join vehicle_companies v 
                       on ( v.company_id = u.company_id) 
                    where u.id  = new.user_id
                      and v.company_id = new.vehicle_company_id 
                      and v.vehicle_id = new.vehicle_company_id     
                 ) 
    then 
       raise exception E'During % on %.%\nUser.company_id does not match vehicle_companies.company_id' ,tg_op,tg_table_schema,tg_table_name; 
    end if;

     return new;
end;
$$;

create or replace trigger user_vehicles_biur
   before insert or update 
   on user_vehicles 
   for each row 
   execute function validate_user_vehicle_company();
      

我在這里整理了一個簡短的演示,其中包含非常簡單的數據值。

這個模式為我解決了它:

create table companies (
    id serial primary key,
    name varchar not null,
    unique(name)
);

create table vehicles (
    id serial primary key,
    name varchar not null,
    unique(name)
);

create table users (
    id serial primary key,
    company_id integer not null,
    name varchar not null,
    unique (id, company_id),
    foreign key (company_id) references companies(id)
);

create table vehicle_companies (
    id serial primary key,
    vehicle_id integer not null,
    company_id integer not null,
    unique (vehicle_id, company_id),
    foreign key (vehicle_id) references vehicles(id),
    foreign key (company_id) references companies(id)
);

create table user_vehicles (
    id serial primary key,
    user_id integer not null,
    vehicle_id integer not null,
    company_id integer not null,
    unique (id),
    unique (vehicle_id, company_id),
    foreign key (user_id, company_id) references users(id, company_id),
    foreign key (vehicle_id, company_id) references vehicle_companies(vehicle_id, company_id)
);

數據庫小提琴

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM