2012-08-22 95 views
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') 
+0

如何增加一个年列'表A'? – Kermit

回答

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) 
); 

后@更新嘘声的评论: 的CHECK约束条件与列DEFAULTNOT 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(); 
+2

如果c_year始终应该是created_at中的年份,那么我也会为此添加CHECK约束。 –

+0

@Catcall:CHECK约束的好建议! (改为“a_year”以保持与问题保持一致。) –

+0

感谢您深思熟虑的建议。我没有真正使用created_at,而是使得DEFAULT失败的published_at(因为您不能基于另一列的值进行默认设置)。发表在任意日期。 –

相关问题