我正在尝试创建一个简单的数据库,其中包含客户数据表和订单数据表。我正在尝试编写一个约束,使得客户无法在特定日期订购超过特定数量的商品。这就是我所拥有的:
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
);
这是我为强制执行此约束所写的内容,但它不起作用。我假设它是因为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
我的问题是如何让这个约束起作用,比如如何限制每天的订单量。
答案 0 :(得分:7)
由于@ruakh已经清理完毕,PostgreSQL中没有CREATE ASSERTION
。只需查看list of SQL commands即可。它不存在。
您可以使用更新每个客户的计数并结合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);
创建触发器功能和触发器:
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();
我在AFTER触发后创造了所有这些触发器 - 这就是RETURN NULL
的原因。在这种情况下,优先于BEFORE。如果任何其他条件可以取消中间的DML语句(如其他触发器),它会表现得更好。
如果您没有任何类型,那么BEFORE触发器可能更可取。在这种情况下,请务必使触发功能相应地返回NEW / OLD。
答案 1 :(得分:3)
我不相信PostgreSQL强制执行CREATE ASSERTION
语句;至少,“断言”在Appendix D.2 of the PostgreSQL Manual中列为不受支持的功能。据我所知,实际上,主要DBMS的 none 强制执行它们。
解决方案是使用trigger代替;您可以将其设置为在ORDERS
上的任何插入之前运行,并在检测到此问题时引发错误。 (我假设ORDERS
上的更新永远不会引入这个问题,但如果可以的话,那么你也需要触发这个案例。)