我创建了三个表:supplier
,item
和purchase
。 supplier
id与item
表有关系,item
id与purchase
表有关系。我不想在同一itemid
项目的purchase
表上插入supplier
。如何设置约束?
CREATE TABLE csupplier(
supid NUMBER(10) PRIMARY KEY ,
supname VARCHAR2(30)
);
CREATE TABLE ctitem(
itemid NUMBER(10) PRIMARY KEY,
itemname VARCHAR2(50),
supid NUMBER(10)
);
ALTER TABLE CTITEM
ADD CONSTRAINT CTITEM_FK1 FOREIGN KEY(SUPID )REFERENCES CSUPPLIER(SUPID );
CREATE TABLE cPurchase(
purchaseid NUMBER(10) PRIMARY KEY,
itemid NUMBER(10),
purchaseqty NUMBER(10)
);
ALTER TABLE CPURCHASE
ADD CONSTRAINT CPURCHASE_FK1 FOREIGN KEY(ITEMID )REFERENCES CTITEM(ITEMID )
答案 0 :(得分:0)
有2种解决方案来解决您的问题: 1.更改表cPurchase,然后在表中添加supid列。并在此列上创建唯一键。这样可以解决您的问题。
CREATE TABLE cPurchase(
purchaseid NUMBER(10) PRIMARY KEY,
itemid NUMBER(10),
purchaseqty NUMBER(10),
supid NUMBER(10) UNIQUE KEY
);
如果无法在此表上进行更改,请在“插入/更新”触发器之前写入行级别。在此触发器中,编写逻辑以根据Item_id算法找到Supid,然后他们找到您的购买表中存在的该供应商的任何项目。
CREATE [ OR REPLACE ] TRIGGER SUP_CHECK
BEFORE INSERT
ON cPurchase
FOR EACH ROW
DECLARE
L_COUNT NUMBER;
BEGIN
SELECT COUNT(*) INTO L_COUNT
FROM cPurchase c
WHERE C.itemid in (Select itemid from ctitem ct where ct.supid = (Select supid
from ctitem where itemid = :new.itemid) );
EXCEPTION
WHEN ...
-- exception handling
END;
答案 1 :(得分:0)
我不想在购买时同时插入item-1和item-3
问题在于Oracle无法同时理解 的概念。它了解事务,了解DML语句,了解唯一键。因此,我们需要用Oracle可以理解的术语来描述您的问题:例如,给定的购买不能包含来自同一供应商的一项以上的商品。
您的第一个问题是您的数据模型不支持这样的规则。您的cpurchase
表的主键为purchaseid
,这意味着您每购买一件商品就有一条记录。没有可以针对其执行规则的一组购买物品。因此,第一件事就是更改数据模型:
CREATE TABLE cPurchase(
purchaseid NUMBER(10) PRIMARY KEY );
CREATE TABLE cPurchaseItem(
purchaseid NUMBER(10),
itemid NUMBER(10),
purchaseqty NUMBER(10)
);
ALTER TABLE CPURCHASEITEM
ADD CONSTRAINT CPURCHASEITEM_PK PRIMARY KEY(PURCHASEID,ITEMID);
ALTER TABLE CPURCHASEITEM
ADD CONSTRAINT CPURCHASEITEM_FK1 FOREIGN KEY(PURCHASEID )REFERENCES CPURCHASE;
ALTER TABLE CPURCHASE
ADD CONSTRAINT CPURCHASE_FK2 FOREIGN KEY(ITEMID )REFERENCES CTITEM(ITEMID );
现在,我们有了一个标头详细结构,可以将多个项目分配给一次购买,这意味着我们可以尝试执行该规则。
下一个问题是supplierid
不是cpurchaseitem
的属性。无法在对另一个表执行查询的表或列上建立检查约束。您所需要的是一个SQL断言,它是一种概念构造,可让我们定义此类规则。 Alas Oracle(以及任何其他RDBMS)目前都支持断言。
因此,我们有三个选择:
cpurchaeitem
进行归一化以包含supplierid
,然后在(purchaseid, supplierid)
上建立唯一约束。每当您填充supplierid
时,您都需要填充cpurchaseitem
。(警告:此代码是通配符,可能包含错误和/或编译错误。)
create or replace trigger cpurchaseitem_trg
after insert or update on cpurchaseitem
declare
rec_count number;
begin
select count(*)
into rec_count
from cpurchaseitem pi
join citem I on pi.itemid = i.itemid
group by pi.purchaseid, i.supplierid having count(*) > 1;
if rec_count > 0 then
raise_application_error(-20000
, 'more than one item for a supplier!');
end if;
end;
坦率地说,这些解决方案都不是特别有吸引力。 API是可靠的解决方案,但可以绕开。随着购买数量随着时间的增长,触发器将遭受扩展问题(尽管可以通过编写复合触发器来缓解,这留给读者练习)。即使不是对最佳实践进行建模,反规范化也是最安全(并且可能是最有效的)解决方案。