以下是我的用例:
我有 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 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 中的“类型”列应该表示表 A、B 或 C 中的哪一个“id”存储在“other_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 的问题相同):
ERROR: syntax error at or near "'A'"
我的问题是,使用外部组合键,可以引用列和固定值吗?如果不是,解决这个问题的更好方法是什么?
最佳答案
我建议另一种设计:
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_id、b_id、c_id
)而不是两列(other_id、type
)。与人们的想法相反,这需要更少 磁盘空间,同时更干净、更简单。您不需要额外的约束或索引来强制执行参照完整性。
NULL
storage is cheap.
如果你想强制执行,那最多的(a, b, c
) 一次可以链接,添加一个CHECK
constraint :
ALTER TABLE x ADD CONSTRAINT x_max1_fk
CHECK (a_id IS NULL AND b_id IS NULL
OR b_id IS NULL AND c_id IS NULL
OR a_id IS NULL AND c_id IS NULL)
看似冗长,但非常廉价和简单。
如果您想要强制执行一次必须链接exactly one (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
请注意我是如何避免列名 id
和 name
的。请改用描述性名称,这会让您在加入几个表时更轻松 - 您将必须对这样的设计做很多事情,而这正是您在关系数据库中做的事情。 p>
我使用 text
而不是 varchar(20)
。 Why?
我也会考虑 ON UPDATE CASCADE
并且可能是外键的 ON DELETE CASCADE
修饰符。
关于sql - 使用外键,可以引用列和固定值吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20504319/