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です。a.created_atこれは100%冗長であり、いつでも派生させることができます。

列が積極的に必要な場合(たとえば、テーブルの特定の基準に対して1年に1行を強制する場合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 に答える