Sql 不直接相关的表的完整性约束
我是一名SQL初学者,我不知道如何正确地为以下情况创建完整性约束: 该模式描述了一个交付系统——每个餐厅都提供一些可以交付给客户的物品(在可见模式之外) 问题出现在Sql 不直接相关的表的完整性约束,sql,oracle,database-design,constraints,Sql,Oracle,Database Design,Constraints,我是一名SQL初学者,我不知道如何正确地为以下情况创建完整性约束: 该模式描述了一个交付系统——每个餐厅都提供一些可以交付给客户的物品(在可见模式之外) 问题出现在in_delivery表中-菜单中的项目通过此表与交货一起注册。根据当前情况,可以将菜单项添加到由餐厅完成的配送,但该餐厅可能不提供菜单项 当在配送中插入时,我需要以某种方式检查菜单项\u MenuItem\u ID是否存在于offers中,该菜单项与表关联的RestaurantID等于RestaurantID 我不知道这里是否可以
in_delivery
表中-菜单中的项目通过此表与交货一起注册。根据当前情况,可以将菜单项
添加到由餐厅
完成的配送
,但该餐厅可能不提供菜单项
当在配送中插入时,我需要以某种方式检查菜单项\u MenuItem\u ID
是否存在于offers
中,该菜单项与表关联的RestaurantID
等于RestaurantID
我不知道这里是否可以使用外键,因为表不是“相邻的”
我们想到的是在的配送中有一家餐厅
,这将是餐厅
和配送
的外键。然后我可以在中找到它。有更好的办法吗
感谢您的帮助您可以通过以下更改强制执行约束:
在送货表的中添加餐厅id
列
在配送(配送id、餐厅id)
上添加唯一约束(3需要)
将外键从配送->配送中的更改为指向(配送标识,餐厅标识)
将外键从配送->菜单项中的更改为配送->优惠中的
或者,可以使用触发器检查约束:
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 )
)
/
SELECT * FROM in_delivery
| DELIVERY_ID | MENU_ITEM_ID |
|-------------|--------------|
| 1 | 1 |
| 2 | 2 |
为了便于阅读,我创建了两个有用的函数(您可能希望其中包含一些异常处理):
然后,只需在表中添加一个触发器,检查餐厅是否提供该项目,如果没有,则引发异常
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:
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 )
)
/
SELECT * FROM in_delivery
| DELIVERY_ID | MENU_ITEM_ID |
|-------------|--------------|
| 1 | 1 |
| 2 | 2 |
:
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 )
)
/
SELECT * FROM in_delivery
| 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 )
这个解决方案并不完全可靠。例如,触发器可能会给出假阴性或假阳性结果,因为它不会“看到”其他事务同时进行的更新(例如,更改与配送或菜单项相关的餐厅)。为了保持健壮性,基于触发器的解决方案需要使用锁定来防止这种更新。但在我看来(基于我对数据集的假设),你不太可能得到这些变化,因为我不知道有哪家餐馆会送货,送货会突然转移到另一家餐馆@Vincent的答案是更好的选择,但是如果表的设计是不变的,那么这是不可能的,这是一个选择。