是否有不同项目的联合表格的模式?

问题描述 投票:0回答:1

我想基于列约束的2列组合。我在这里找不到使用外键的方法,因为它应该是有条件的FK,然后。希望这个基本的SQL显示问题:

CREATE TABLE performer_type (
  id serial primary key,
  type varchar
);

INSERT INTO performer_type ( id, type ) VALUES (1, 'singer'), ( 2, 'band');

CREATE TABLE singer (
  id serial primary key,
  name varchar
);

INSERT INTO singer ( id, name ) VALUES (1, 'Robert');

CREATE TABLE band (
  id serial primary key,
  name varchar
);

INSERT INTO band ( id, name ) VALUES (1, 'Animates'), ( 2, 'Zed Leppelin');

CREATE TABLE gig (
  id serial primary key,
  performer_type_id int default null, /* FK, no problem */
  performer_id int default null       /* want FK based on previous FK, no good solution so far */
);

INSERT INTO gig ( performer_type_id, performer_id ) VALUES ( 1,1 ), (2,1), (2,2), (1,2), (2,3);

现在,最后一个INSERT工作,但是对于最后2个值对,我希望它失败,因为没有歌手ID 2也没有带ID 3.如何设置这样的约束?

我已经问过类似的question in Mysql context,只有解决方案是使用触发器。触发器的问题是:您不能拥有类型和表集的动态列表。我想动态添加类型(和相关表)。

我也找到了very promising pattern,但这对我来说是颠倒的,我没想通,如何让它在我的情况下工作。

我在这里看起来似乎是如此有用的模式,我认为必须有一些共同的方式。是吗?

编辑。

似乎,我在我的例子中选择了不好的项目,所以我试着说清楚:不同的表演者表(singerband)之间没有任何关系。 gig-table只需列出不同表演者的任务,而不必在他们之间设置任何关系。

另一个例子是库存中的物品:我可能有item_type-table,它定义了数百个具有相关表格的项目类型(例如,orangehouse),并且应该有表格stock,其中包含所有项目的外观。

我使用的PostgreSQL是9.6

postgresql
1个回答
0
投票

基于@Laurenz Albe answer我在上面形成了一个解决方案。主要区别:有父表performer,PK是特定执行者表的FK / PK,也可以从gig表中引用。

CREATE TABLE performer_type (
  id serial primary key,
  type varchar
);
INSERT INTO performer_type ( id, type ) VALUES (1, 'singer' ), ( 2, 'band' );

CREATE TABLE performer (
  id serial primary key,
  performer_type_id int REFERENCES performer_type(id)
);

CREATE TABLE singer (
  id int primary key REFERENCES performer(id),
  name varchar
);

INSERT INTO performer ( performer_type_id ) VALUES (1); -- get PK 1 for next statement
INSERT INTO singer ( id, name ) VALUES (1, 'Robert');

CREATE TABLE band (
  id int primary key REFERENCES performer(id),
  name varchar
);

INSERT INTO performer ( performer_type_id ) VALUES (2); -- get PK 2 for next statement
INSERT INTO singer ( id, name ) VALUES (2, 'Animates');
INSERT INTO performer ( performer_type_id ) VALUES (2); -- get PK 3 for next statement
INSERT INTO singer ( id, name ) VALUES (3, 'Zed Leppelin');

CREATE TABLE gig (
  id serial primary key,
  performer_id int REFERENCES performer(id)
);

INSERT INTO gig ( performer_id ) VALUES (1), (2), (3), (4);

最后一次INSERT失败,如预期的那样:

ERROR:  insert or update on table "gig" violates foreign key constraint "gig_performer_id_fkey"
DETAIL:  Key (performer_id)=(4) is not present in table "performer".

对我来说有一个令人讨厌的问题:我没有好的方法来区分哪个ID是歌手和哪个乐队等(原始例子中我在performer_type_id表中有gig),因为任何performer_id都可能属于任何表演者。所以我想任何表演者类型都有它自己的ID范围,所以我为每个序列创建了一个虚拟表

CREATE TABLE band_id (
  id int primary key,
  dummy boolean default null
);
CREATE SEQUENCE band_id_seq START 1;
ALTER TABLE band_id ALTER COLUMN id SET DEFAULT nextval('band_id_seq');

CREATE TABLE singer_id (
  id int primary key,
  dummy boolean default null
);
CREATE SEQUENCE singer_id_seq START 2000000;
ALTER TABLE singer_id ALTER COLUMN id SET DEFAULT nextval('singer_id_seq');

现在,要将新行插入特定的执行者表,我必须为它获取下一个ID:

INSERT INTO band_id (dummy) VALUES (NULL);

试图弄清楚,是否可以在数据库级别上解决此过程,或者在应用程序级别中完成某些任务。如果插入band表可能会很好:

  • 在触发插入qazxsw poi之前生成特定ID
  • 在触发将此新ID插入band_id-table之前
  • 将这个新ID包含在插入performer的INSERT中

前两点很容易,但最后一点目前尚不清楚。

© www.soinside.com 2019 - 2024. All rights reserved.