我是一个SQL初学者,我无法弄清楚如何在这样的情况下正确创建完整性约束:
架构描述了一个交付系统 - 每个餐厅都提供一些项目,这些项目可以交付给客户(在可见模式之外)。
问题来自in_delivery
表 - 菜单中的项目通过此表注册。根据当前的状态,可以menu_item
添加delivery
,restaurant
由in_delivery
完成,但该餐厅可能不会提供menu_item!
当插入Menu_Item_MenuItem_ID
时,如果offers
中存在Restaurant_RestaurantID
RestaurantID
,Delivery
等于RestaurantID
,我需要以某种方式检查{ {1}}与表格相关联。
我不知道我是否可以在这里使用外键,因为表格不是“相邻”..
我想到的是in_delivery
中Restaurant
Delivery
,offers
和{{1}}都是外键。然后我可以在{{1}}中找到它。还有更好的方法吗?
感谢您的帮助
答案 0 :(得分:2)
您可以通过以下更改强制执行约束:
restaurant_id
表in_delivery
列
delivery (delivery_id, restaurant_id)
上添加一个唯一约束(需要3。)in_delivery -> delivery
更改为指向(delivery_id, restaurant_id)
in_delivery -> menu_item
更改为in_delivery -> offers
答案 1 :(得分:0)
或者,您可以使用触发器来检查约束:
Oracle 11g R2架构设置:
CREATE TABLE Restaurants (
RestaurantID NUMBER(2) PRIMARY KEY,
Name VARCHAR2(30) NOT NULL
)
/
INSERT INTO Restaurants
SELECT 1, 'Soylent Green Express' FROM DUAL
UNION ALL SELECT 2, 'Helga''s House of Ribs' FROM DUAL
/
CREATE TABLE Menu_Items (
Menu_Item_ID NUMBER(2) PRIMARY KEY,
Name VARCHAR2(20) NOT NULL
)
/
INSERT INTO Menu_Items
SELECT 1, 'Soylent Green' FROM DUAL
UNION ALL SELECT 2, 'Ribs' FROM DUAL
/
CREATE TABLE Offers (
RestaurantID NUMBER(2),
Menu_Item_ID NUMBER(2),
PRIMARY KEY ( RestaurantID, Menu_Item_ID ),
FOREIGN KEY ( RestaurantID ) REFERENCES Restaurants ( RestaurantID ),
FOREIGN KEY ( Menu_Item_ID ) REFERENCES Menu_Items ( Menu_Item_ID )
)
/
INSERT INTO Offers
SELECT 1, 1 FROM DUAL
UNION ALL SELECT 2, 2 FROM DUAL
/
CREATE TABLE Deliveries (
RestaurantID NUMBER(2) NOT NULL,
Delivery_ID NUMBER(2) PRIMARY KEY,
FOREIGN KEY ( RestaurantID ) REFERENCES Restaurants ( RestaurantID )
)
/
INSERT INTO Deliveries
SELECT 1, 1 FROM DUAL
UNION ALL SELECT 2, 2 FROM DUAL
/
CREATE TABLE in_delivery (
Delivery_ID NUMBER(2),
Menu_Item_ID NUMBER(2),
PRIMARY KEY ( Delivery_ID, Menu_Item_ID ),
FOREIGN KEY ( Delivery_ID ) REFERENCES Deliveries ( Delivery_ID ),
FOREIGN KEY ( Menu_Item_ID ) REFERENCES Menu_Items ( Menu_Item_ID )
)
/
为了便于阅读,我创建了两个有用的函数(您可能希望在其中进行一些异常处理):
CREATE OR REPLACE FUNCTION get_Delivery_RestaurantID (
p_Delivery_ID Deliveries.Delivery_ID%TYPE
) RETURN Restaurants.RestaurantID%TYPE
AS
v_RestaurantID Restaurants.RestaurantID%TYPE;
BEGIN
SELECT RestaurantID
INTO v_RestaurantID
FROM Deliveries
WHERE Delivery_ID = p_Delivery_ID;
RETURN v_RestaurantID;
END get_Delivery_RestaurantID;
/
CREATE OR REPLACE FUNCTION does_Restaurant_Offer_Item (
p_RestaurantID Restaurants.RestaurantID%TYPE,
p_Menu_Item_ID Menu_Items.Menu_Item_ID%TYPE
) RETURN NUMBER
AS
v_exists NUMBER(1);
BEGIN
SELECT CASE WHEN EXISTS ( SELECT 1
FROM Offers
WHERE RestaurantID = p_RestaurantID
AND Menu_Item_ID = p_Menu_Item_ID
)
THEN 1
ELSE 0
END
INTO v_exists
FROM DUAL;
RETURN v_exists;
END does_Restaurant_Offer_Item;
/
然后只需在表格中添加一个触发器,检查餐厅是否提供该项目,如果没有,则提出异常。
CREATE TRIGGER check_Valid_Delivery_Item
BEFORE INSERT OR UPDATE OF Delivery_ID, Menu_Item_ID
ON in_delivery
FOR EACH ROW
BEGIN
IF does_restaurant_Offer_Item( get_Delivery_RestaurantID( :new.Delivery_ID ), :new.Menu_Item_ID ) = 0
THEN
RAISE_APPLICATION_ERROR (-20100, 'Invalid Delivery Item');
END IF;
END check_Valid_Delivery_Item;
/
INSERT INTO in_delivery VALUES( 1, 1 )
/
INSERT INTO in_delivery VALUES( 2, 2 )
/
查询1 :
SELECT * FROM in_delivery
<强> Results 强>:
| DELIVERY_ID | MENU_ITEM_ID |
|-------------|--------------|
| 1 | 1 |
| 2 | 2 |
如果您尝试这样做:
INSERT INTO in_delivery VALUES( 1, 2 );
然后你得到:
ORA-20100: Invalid Delivery Item ORA-06512: at "USER_4_F9593.CHECK_VALID_DELIVERY_ITEM", line 4 ORA-04088: error during execution of trigger 'USER_4_F9593.CHECK_VALID_DELIVERY_ITEM' : INSERT INTO in_delivery VALUES( 1, 2 )