我有一个带有时间戳字段的表,我在其上创建了一个复合索引。
CREATE INDEX "IDX_NAME_A" ON TABLE "A" (a_id, extract(year FROM created_at))
我有另一个存储一年的表和a_id,我想要一个外键关系。
我似乎无法找到我想要的语法。
ALTER TABLE "B"
ADD FOREIGN KEY(a_id, a_year)
REFERENCES A(a_id, extract(YEAR FROM created_at));
产生
ERROR: syntax error at or near "("
我也试过......
ALTER TABLE "B"
ADD FOREIGN KEY(a_id, a_year)
USING INDEX "IDX_NAME_A";
任何想法?
Table A
--------
a_id serial,
created_at timestamp default now()
Table B
-------
b_id serial
a_id integer not null,
a_year date_part('year')
答案 0 :(得分:5)
外键约束无法引用索引。它必须是一张桌子 外键约束不能引用表达式。它必须指向引用表的列名 并且必须在引用列的集合上存在唯一索引(主键也是隐式的)。
首先阅读the manual about foreign keys here。
优越的设计是删除列b.a_year
。它是100%冗余的,可以随时从a.created_at
派生。
如果您确实需要该列(例如,对于表b
中的某些条件,每年强制执行一行),您可以实现这样的目标:
CREATE TABLE a (
a_id serial
,created_at timestamp NOT NULL DEFAULT now()
,a_year NOT NULL DEFAULT extract(year FROM now())::int -- redundant, for fk
,CHECK (a_year = extract(year FROM created_at)::int)
);
CREATE UNIQUE INDEX a_id_a_year_idx ON TABLE a (a_id, a_year); -- needed for fk
CREATE TABLE b (
b_id serial
,a_id integer NOT NULL
,a_year int -- doesn't have to be NOT NULL, but might
,CONSTRAINT id_year FOREIGN KEY (a_id, a_year) REFERENCES a(a_id, a_year)
);
@ Catcall评论后更新:
CHECK
约束与列DEFAULT
和NOT NULL
条款相结合可以强制执行您的制度。
或者(不太简单,但允许NULL
值)您可以使用trigger维护a.a_year
中的值:
CREATE OR REPLACE FUNCTION trg_a_insupbef()
RETURNS trigger AS
$BODY$
BEGIN
NEW.a_year := extract(year FROM NEW.created_at)::int;
RETURN NEW;
END;
$BODY$
LANGUAGE plpgsql VOLATILE;
CREATE TRIGGER insupbef
BEFORE INSERT OR UPDATE ON a
FOR EACH ROW EXECUTE PROCEDURE trg_a_insupbef();