添加约束的不同方法有哪些,以便只能插入在订单日期可用的项目?
What are the different ways of adding a constraint so that only items that are available on the order date can be inserted?
order.date 必须在 item.date_from 和 item.date_to 之间...有哪些不同的方法?
CREATE TABLE "item" (
"id" SERIAL PRIMARY KEY,
"date_from" DATE NOT NULL,
"date_to" DATE NOT NULL
);
CREATE TABLE "order" (
"id" SERIAL PRIMARY KEY,
"date" DATE NOT NULL
);
CREATE TABLE "order_item" (
"order" INTEGER NOT NULL REFERENCES "order",
"item" INTEGER NOT NULL REFERENCES "item"
);
一个测试例子:
CREATE OR REPLACE FUNCTION public.item_date()
RETURNS trigger
LANGUAGE plpgsql
AS $function$
DECLARE
order_date date;
from_date date;
to_date date;
BEGIN
select into order_date "date" from "order" where id = new.order;
select into from_date, to_date date_from, date_to from item where id = new.item;
--Use date range to test whether order date is in item date range.
if order_date <@ daterange(from_date, to_date, '[]') then
return new;
else
return null;
end if;
END;
$function$
create trigger item_date_check before insert or update on order_item for each row execute function item_date();
insert into item values (1, '09/01/2021', '10/31/2021');
insert into item values (2, '07/01/2021', '08/31/2021');
insert into "order" values (1, '09/05/2021');
insert into order_item values (1, 1);
NOTICE: Order date 2021-09-05, from_date 2021-09-01, to_date 2021-10-31
INSERT 0 1
--Returning NULL causes the INSERT not to happen.
insert into order_item values (1, 2);
NOTICE: Order date 2021-09-05, from_date 2021-07-01, to_date 2021-08-31
INSERT 0 0
请注意,我必须引用“order”,因为它也是一个保留字。你可以看看 Key(reserved) Words. For range
functions/operators see Range Function. For general information on range
(s) see Range Types
检查约束适用于简单表达式。例如,对订单进行简单的完整性检查:check( date > '2010-01-01')
。还有exclusion constraints which check no two rows have the same value as defined by the exclusion. But, with the exception of foreign key constraints,约束不查询其他tables.
你可以通过 insert
和 update
上的触发器来解决这个问题,我将在下面进行介绍,但最好用参照完整性来解决这类问题。但是,我想不出办法。
您可以查看订单的可用商品。这里</code>是订单日期。</p>
<pre><code>create temporary view items_available_to_order
select *
-- pluralize table names to avoid conflicting with keywords and columns
from items
-- date_from and date_to has become a single daterange when_available
where items.when_available @>
然后只插入该视图中的项目。
如果你想走触发路线(你可以两者都做)写一个函数来检查订单的项目是否有效。它要么引发异常,要么引发 returns 触发器。 new
是插入的行,或更新后的行。
我更改了一些 table 和列名称和类型以避免常见的陷阱。
create function check_item_order_is_valid()
returns trigger
language 'plpgsql'
as $body$
declare
item_is_available boolean;
begin
select
items.when_available @> orders.ordered_on into item_is_available
from item_orders
join items on items.id = new.order_id
join orders on orders.id = new.item_id;
if( not item_is_available) then
raise exception 'Item #% is not available for order #%',
new.item_id, new.order_id;
end if;
return new;
end
$body$
然后定义一个触发器,在 item/order table.
中插入或更新行时调用该函数
create trigger check_item_orders
before insert or update
on item_orders
for each row
execute function check_item_order_is_valid();
如果项目的有效范围发生变化怎么办?您需要对项目进行更新触发器以检查其订单是否仍然有效。可能是。取决于您的业务逻辑。
order.date 必须在 item.date_from 和 item.date_to 之间...有哪些不同的方法?
CREATE TABLE "item" (
"id" SERIAL PRIMARY KEY,
"date_from" DATE NOT NULL,
"date_to" DATE NOT NULL
);
CREATE TABLE "order" (
"id" SERIAL PRIMARY KEY,
"date" DATE NOT NULL
);
CREATE TABLE "order_item" (
"order" INTEGER NOT NULL REFERENCES "order",
"item" INTEGER NOT NULL REFERENCES "item"
);
一个测试例子:
CREATE OR REPLACE FUNCTION public.item_date()
RETURNS trigger
LANGUAGE plpgsql
AS $function$
DECLARE
order_date date;
from_date date;
to_date date;
BEGIN
select into order_date "date" from "order" where id = new.order;
select into from_date, to_date date_from, date_to from item where id = new.item;
--Use date range to test whether order date is in item date range.
if order_date <@ daterange(from_date, to_date, '[]') then
return new;
else
return null;
end if;
END;
$function$
create trigger item_date_check before insert or update on order_item for each row execute function item_date();
insert into item values (1, '09/01/2021', '10/31/2021');
insert into item values (2, '07/01/2021', '08/31/2021');
insert into "order" values (1, '09/05/2021');
insert into order_item values (1, 1);
NOTICE: Order date 2021-09-05, from_date 2021-09-01, to_date 2021-10-31
INSERT 0 1
--Returning NULL causes the INSERT not to happen.
insert into order_item values (1, 2);
NOTICE: Order date 2021-09-05, from_date 2021-07-01, to_date 2021-08-31
INSERT 0 0
请注意,我必须引用“order”,因为它也是一个保留字。你可以看看 Key(reserved) Words. For range
functions/operators see Range Function. For general information on range
(s) see Range Types
检查约束适用于简单表达式。例如,对订单进行简单的完整性检查:check( date > '2010-01-01')
。还有exclusion constraints which check no two rows have the same value as defined by the exclusion. But, with the exception of foreign key constraints,约束不查询其他tables.
你可以通过 insert
和 update
上的触发器来解决这个问题,我将在下面进行介绍,但最好用参照完整性来解决这类问题。但是,我想不出办法。
您可以查看订单的可用商品。这里</code>是订单日期。</p>
<pre><code>create temporary view items_available_to_order
select *
-- pluralize table names to avoid conflicting with keywords and columns
from items
-- date_from and date_to has become a single daterange when_available
where items.when_available @>
然后只插入该视图中的项目。
如果你想走触发路线(你可以两者都做)写一个函数来检查订单的项目是否有效。它要么引发异常,要么引发 returns 触发器。 new
是插入的行,或更新后的行。
我更改了一些 table 和列名称和类型以避免常见的陷阱。
create function check_item_order_is_valid()
returns trigger
language 'plpgsql'
as $body$
declare
item_is_available boolean;
begin
select
items.when_available @> orders.ordered_on into item_is_available
from item_orders
join items on items.id = new.order_id
join orders on orders.id = new.item_id;
if( not item_is_available) then
raise exception 'Item #% is not available for order #%',
new.item_id, new.order_id;
end if;
return new;
end
$body$
然后定义一个触发器,在 item/order table.
中插入或更新行时调用该函数create trigger check_item_orders
before insert or update
on item_orders
for each row
execute function check_item_order_is_valid();
如果项目的有效范围发生变化怎么办?您需要对项目进行更新触发器以检查其订单是否仍然有效。可能是。取决于您的业务逻辑。