Sql 使用外部复合键,是否可以引用列和固定值?
以下是我的用例: 我有4张桌子:Sql 使用外部复合键,是否可以引用列和固定值?,sql,database,postgresql,database-design,foreign-keys,Sql,Database,Postgresql,Database Design,Foreign Keys,以下是我的用例: 我有4张桌子: CREATE TABLE A ( name character(20) NOT NULL, id integer NOT NULL, CONSTRAINT a_pkey PRIMARY KEY (id) ) CREATE TABLE B ( name character(20) NOT NULL, id integer NOT NULL, CONSTRAINT b_pkey PRIMARY KEY (id) ) CREATE TABL
CREATE TABLE A
(
name character(20) NOT NULL,
id integer NOT NULL,
CONSTRAINT a_pkey PRIMARY KEY (id)
)
CREATE TABLE B
(
name character(20) NOT NULL,
id integer NOT NULL,
CONSTRAINT b_pkey PRIMARY KEY (id)
)
CREATE TABLE C
(
name character(20) NOT NULL,
id integer NOT NULL,
CONSTRAINT c_pkey PRIMARY KEY (id)
)
CREATE TABLE X
(
type character(20) NOT NULL,
other_id integer NOT NULL,
id integer NOT NULL,
CONSTRAINT "X_PK" PRIMARY KEY (id)
)
表X中的“other_id”可以是表A、B或C中任何一个的“id”。表X中的“type”列应指示“other_id”中存储了表A、B或C中的哪一个“id”
表x中的示例数据:
type other_id id
"A" 1 1
"B" 1 2
"C" 1 3
"A" 2 4
尝试使用固定值在表X-A、X-B和X-C之间创建复合FK,如下所示
ALTER TABLE x
ADD CONSTRAINT X_A_FK FOREIGN KEY (other_id, type) REFERENCES a (id, 'A') ON DELETE CASCADE
但是我得到了这个错误(所有FK都有相同的问题):
错误:“A”处或附近出现语法错误
我的问题是,使用外部复合键,是否可以引用列和固定值?如果不是的话,有什么更好的方法来解决这个问题呢?根据您遇到的错误,这是不可能的。但至少有两种选择可以实现相同的效果:
类型上添加检查
约束,并在(其他id)
或(其他id,类型)
上强制使用外键
我建议另一种设计:
CREATE TABLE a (
a_id integer PRIMARY KEY -- pk is NOT NULL automatically
,a text NOT NULL
);
CREATE TABLE b ( ...);
CREATE TABLE c ( ...);
CREATE TABLE x (
x_id integer PRIMARY KEY -- or maybe a serial?
,a_id integer REFERENCES a(a_id) -- can be NULL
,b_id integer REFERENCES b(b_id)
,c_id integer REFERENCES c(c_id)
);
主要的一点是在设计中有三列(a\u id,b\u id,c\u id
),而不是两列(other\u id,type
)。与人们的想法相反,这需要更少的磁盘空间,同时更干净、更简单。您不需要额外的约束或索引来强制引用完整性。如果您想强制执行,一次最多可以链接一个(
a,b,c
),请添加一个:
看起来很长,但非常便宜和简单
如果您希望强制一次只能链接一个(a,b,c
),请修改为:
ALTER TABLE x ADD CONSTRAINT x_exactly1_fk
CHECK (a_id IS NULL AND b_id IS NULL AND c_id IS NOT NULL
OR b_id IS NULL AND c_id IS NULL AND a_id IS NOT NULL
OR a_id IS NULL AND c_id IS NULL AND b_id IS NOT NULL)
对于不仅仅是几列的,我会使用:
ALTER TABLE x ADD CONSTRAINT x_exactly1_fk
CHECK ((a_id IS NULL)::int
+ (b_id IS NULL)::int
+ (c_id IS NULL)::int = 1) -- or <= 1 for the former case
ALTER TABLE x ADD CONSTRAINT x_精确1_fk
检查((a_id为空)::int
+(b_id为空)::int
+(c_id为NULL)::int=1)--或者感谢您的快速回复,请您对您的第一个解决方案进行详细说明,我不知道如何实现它。我可能应该补充说我需要3个FK,我在问题中只提到了一个,因为我尝试制作的第一个FK失败了。谢谢你的回复。我曾考虑添加额外的可空列,但不确定这是否是一种好的做法,因为如果将来有更多的表,如a、B和C,我将需要创建更多可空列。我非常感谢您的检查建议,它非常方便且干净,可以确保数据的完整性。@IdaN:如果您有几十个引用表,并且只有一个表适用,(id,type)
会更有利。不过,我想问一个问题,您是否不能将引用的表捆绑到一个(中间)表中或使用…在我的例子中,我只有几个表,您当前的解决方案完全适用。我问这个问题只是想知道你的看法,在一个比两张桌子大得多的案例中,什么是更好的方法。
ALTER TABLE x ADD CONSTRAINT x_exactly1_fk
CHECK ((a_id IS NULL)::int
+ (b_id IS NULL)::int
+ (c_id IS NULL)::int = 1) -- or <= 1 for the former case