假设我们有两个表如下
CREATE TABLE calendar_month (
id serial PRIMARY KEY,
start_date date NOT NULL,
end_date date NOT NULL,
reporting_month character varying(50) NOT NULL
);
CREATE TABLE calendar (
id serial PRIMARY KEY,
holiday bool NOT NULL,
actual_date date NOT NULL
);
如果没有使用触发器,是否有办法确保在日历表中输入的任何actual_date在calendar_month表中始终具有相应的reporting_month,它可以引用?
答案 0 :(得分:6)
如果您可以稍微更改一下表,可以使用外键和检查约束来执行此操作:
CREATE TABLE calendar_month (
id serial PRIMARY KEY,
start_date date NOT NULL UNIQUE,
end_date date NOT NULL,
reporting_month character varying(50) NOT NULL
);
CREATE TABLE calendar (
id serial PRIMARY KEY,
month_start_date date NOT NULL REFERENCES calendar_month(start_date),
holiday bool NOT NULL,
actual_date date NOT NULL CHECK (
actual_date>=month_start_date and
actual_date<(month_start_date+'1 month'::interval)::date)
);
编辑:Mohan已经说过“日历行中的end_date不一定是= start_date + 1个月间隔”。假设我们不能对这几个月的实际sart和结束日期作出任何假设,我们必须稍微做一些事情(正如Mohan自己建议的那样):
CREATE TABLE calendar_month (
id serial PRIMARY KEY,
start_date date NOT NULL,
end_date date NOT NULL,
reporting_month character varying(50) NOT NULL,
UNIQUE(start_date, end_date)
);
CREATE TABLE calendar (
id serial PRIMARY KEY,
month_start_date date NOT NULL,
month_end_date date NOT NULL,
holiday bool NOT NULL,
foreign key(month_start_date, month_end_date)
REFERENCES calendar_month(start_date, end_date) )
actual_date date NOT NULL
CHECK (actual_date>=month_start_date and actual_date<month_end_date)
);
或者actual_date<month_end_date
actual_date<=month_end_date
约束中的check
可能是{{1}} - 这取决于您如何定义月份范围。
答案 1 :(得分:1)
没有
根据提供的CREATE TABLE语句,触发器是您唯一的选择。
答案 2 :(得分:1)
如果你的calendar_month从月的第一天开始(看似合乎逻辑):
CREATE TABLE calendar_month (
start_date DATE PRIMARY KEY CHECK( start_date = date_trunc( 'month', start_date )),
reporting_month TEXT NOT NULL
);
INSERT INTO calendar_month( start_date, reporting_month ) VALUES
('2010-01-01','january 2010'),
('2010-02-01','february 2010');
CREATE TABLE calendar (
id serial PRIMARY KEY,
month_date DATE NOT NULL REFERENCES calendar_month(start_date),
actual_date DATE NOT NULL CHECK ( month_date = date_trunc( 'month', actual_date ) )
);
CREATE OR REPLACE FUNCTION calendar_default_trigger_f() RETURNS trigger AS $$
BEGIN
NEW.month_date = date_trunc( 'month', NEW.actual_date );
RETURN NEW;
END
$$ LANGUAGE plpgsql;
CREATE TRIGGER calendar_default_trigger BEFORE INSERT OR UPDATE ON calendar
FOR EACH ROW EXECUTE PROCEDURE calendar_default_trigger_f();
INSERT INTO calendar (actual_date) VALUES ('2010-01-12'),('2010-01-31'),('2010-02-28');
test=> SELECT * FROM calendar;
id | month_date | actual_date
----+------------+-------------
2 | 2010-01-01 | 2010-01-12
3 | 2010-01-01 | 2010-01-31
4 | 2010-02-01 | 2010-02-28
INSERT INTO calendar (actual_date) VALUES ('2010-04-12');
ERREUR: une instruction insert ou update sur la table « calendar » viole la contrainte de clé
étrangère « calendar_month_date_fkey »
DÉTAIL : La clé (month_date)=(2010-04-01) n'est pas présente dans la table « calendar_month ».
这使用了一个触发器,但它只是为了方便起见。实际检查由外键完成。