1

我有一个带有时间戳字段的表,我在该表上创建了一个复合索引。

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')
4

1 回答 1

5

外键约束不能引用索引。它必须是一张桌子。
外键约束不能引用表达式。它必须指向被引用表的列名。
并且必须在引用的列集上存在唯一索引(主键也隐含地限定)。

首先在这里阅读有关外键的手册


上乘的设计将只是删除列b.a_year。它是 100% 冗余的,可以从a.created_at任何时间派生出来。

如果您确实需要该列(例如,对于 table 中的某些条件每年强制执行一行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结合列DEFAULTNOT NULL子句的约束强制执行您的制度。

或者(不太简单,但允许NULL值)您可以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();
于 2012-08-22T20:09:11.387 回答