基于索引名称而不是表(列)创建外键

Dav*_*han 1 sql postgresql indexing foreign-keys

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

CREATE INDEX "IDX_NAME_A" ON TABLE "A" (a_id, extract(year FROM created_at))
Run Code Online (Sandbox Code Playgroud)

我有另一个表存储一年和a_id我希望有一个外键关系.

我似乎无法找到做我想要的语法.

ALTER TABLE "B" 
  ADD FOREIGN KEY(a_id, a_year) 
  REFERENCES A(a_id, extract(YEAR FROM created_at));
Run Code Online (Sandbox Code Playgroud)

生产:

ERROR:  syntax error at or near "("
Run Code Online (Sandbox Code Playgroud)

我也试过......

ALTER TABLE "B"
  ADD FOREIGN KEY(a_id, a_year) 
  USING INDEX "IDX_NAME_A";
Run Code Online (Sandbox Code Playgroud)

有任何想法吗?

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')
Run Code Online (Sandbox Code Playgroud)

Erw*_*ter 5

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

首先阅读有关外键的手册.


优越的设计就是放下色谱柱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)
);
Run Code Online (Sandbox Code Playgroud)

@ 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();
Run Code Online (Sandbox Code Playgroud)

  • 如果c_year总是应该是created_at中的年份,我也会为它添加一个CHECK约束. (2认同)