ges*_*alt 4 sql postgresql triggers constraints plpgsql
我正在尝试创建一个简单的数据库,其中有一个客户数据表和一个订单数据表.我正在尝试编写一个约束,使得客户无法在特定日期订购超过特定数量的商品.这就是我所拥有的:
CREATE TABLE CUSTOMER
(
CUSTOMER_NUM CHAR(3) PRIMARY KEY,
CUSTOMER_NAME CHAR(35) NOT NULL,
STREET CHAR(15),
CITY CHAR(15),
STATE CHAR(3),
ZIP CHAR(5),
);
CREATE TABLE ORDERS
(
ORDER_NUM CHAR(5) PRIMARY KEY,
ORDER_DATE DATE,
CUSTOMER_NUM CHAR(3),
CONSTRAINT CUSTOMER_NUM_FKEY FOREIGN KEY (CUSTOMER_NUM)
REFRENCES CUSTOMER (CUSTOMER_NUM) MATCH SIMPLE
ON UPDATE CASCADE ON DELETE CASCADE
);
Run Code Online (Sandbox Code Playgroud)
这就是我为强制执行此约束而编写的内容,但它不起作用.我假设它是因为ORDER_NUM和ORDER_DATE永远不会有相同的值.
CREATE ASSERTION ITEM_LIMIT
CEHCK(
( SELECT COUNT(*)
FROM CUSTOMER C1, ORDERS O1
WHERE C1.CUSTOMER_NUM = O1.CUSTOMER_NUM AND
O1.ORDER_DATE = O1.ORDER_NUM
) <= 1000
Run Code Online (Sandbox Code Playgroud)
我的问题是如何使这个约束起作用,比如如何限制每天的订单量.
由于@ruakh已经清理完毕,CREATE ASSERTIONPostgreSQL中没有.只需检查SQL命令列表即可.它不在那里.
您可以使用更新每个客户的计数与CHECK约束相结合的触发器,但您必须涵盖所有相关的DML语句:INSERT,UPDATE,DELETE.看起来像这样:
准备现有客户表:
ALTER TABLE customer ADD COLUMN order_ct integer DEFAULT 0;
UPDATE customer SET order_ct = 0;
ALTER TABLE customer ALTER order_ct SET NOT NULL;
ALTER TABLE customer ADD CONSTRAINT order_ct_max1000 CHECK (order_ct <= 1000);
Run Code Online (Sandbox Code Playgroud)
创建触发器函数和触发器:
CREATE OR REPLACE FUNCTION trg_order_upaft()
RETURNS trigger AS
$BODY$
BEGIN
IF OLD.customer_num <> NEW.customer_num THEN
UPDATE customer
SET order_ct = order_ct - 1
WHERE customer_num = OLD.customer_num;
UPDATE customer
SET order_ct = order_ct + 1
WHERE customer_num = NEW.customer_num;
END IF;
RETURN NULL;
END;
$BODY$
LANGUAGE plpgsql;
CREATE TRIGGER upaft
AFTER UPDATE ON orders FOR EACH ROW
EXECUTE PROCEDURE trg_order_upaft();
CREATE OR REPLACE FUNCTION trg_order_insaft()
RETURNS trigger AS
$BODY$
BEGIN
UPDATE customer
SET order_ct = order_ct + 1
WHERE customer_num = NEW.customer_num;
RETURN NULL;
END;
$BODY$
LANGUAGE plpgsql;
CREATE TRIGGER insaft
AFTER INSERT ON orders FOR EACH ROW
EXECUTE PROCEDURE trg_order_insaft();
CREATE OR REPLACE FUNCTION trg_order_delaft()
RETURNS trigger AS
$BODY$
BEGIN
UPDATE customer
SET order_ct = order_ct - 1;
WHERE customer_num = OLD.customer_num;
RETURN NULL;
END;
$BODY$
LANGUAGE plpgsql;
CREATE TRIGGER delaft
AFTER DELETE ON orders FOR EACH ROW
EXECUTE PROCEDURE trg_order_delaft();
Run Code Online (Sandbox Code Playgroud)
我在AFTER触发器之后做了所有这些触发器 - 这就是为什么它可以RETURN NULL.在这种情况下,优先于BEFORE.如果任何其他条件可以取消中间的DML语句(如其他触发器),它会表现得更好.
如果您没有任何类型,那么BEFORE触发器可能更可取.在这种情况下,请务必使触发功能相应地返回NEW/OLD.
我不相信 PostgreSQL 强制执行CREATE ASSERTION语句;至少,“断言”在PostgreSQL 手册的附录 D.2中被列为不支持的功能。据我所知,实际上,没有一个主要的 DBMS 强制执行它们。
解决方案是使用触发器来代替;您可以将其设置为在任何插入之前运行ORDERS,并在检测到此问题时引发错误。(我认为更新永远不会引入ORDERS这个问题,但如果可以,那么您也需要针对这种情况的触发器。)