我希望基于列约束的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,但这对我来说是颠倒的,我没想通,如何让它在我的情况下发挥作用。
我在这看起来似乎对我这么有用的模式,我认为必须有一些共同的方式。是吗?
修改
似乎,我在我的示例中选择了不好的项目,所以我尝试说清楚:不同的表演者表(singer
和band
)之间有 NO 关系。 gig
- 表只需列出不同表演者的任务,而不必在他们之间设置任何关系。
另一个例子是库存中的物品:我可能有item_type
- 表,它定义了数百种具有相关表格的项目类型(例如,orange
和house
),并且应该是表格stock
,其中包含所有项目的外观。
我使用的PostgreSQL是9.6
答案 0 :(得分: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');
现在,要在特定的perfomer表中插入新行,我必须为它获取下一个ID:
INSERT INTO band_id (dummy) VALUES (NULL);
试图弄清楚,是否可以在数据库级别上解决此过程,或者在应用程序级别中完成某些任务。如果插入band
表可以:
band_id
以生成特定ID performer
- 表band
第2点很容易,但最后一点目前尚不清楚。