表格的完整性约束不是立即相关的

时间:2013-11-29 13:01:01

标签: sql oracle database-design constraints

我是一个SQL初学者,我无法弄清楚如何在这样的情况下正确创建完整性约束: enter image description here

架构描述了一个交付系统 - 每个餐厅都提供一些项目,这些项目可以交付给客户(在可见模式之外)。

问题来自in_delivery表 - 菜单中的项目通过此表注册。根据当前的状态,可以menu_item添加deliveryrestaurantin_delivery完成,但该餐厅可能不会提供menu_item!

当插入Menu_Item_MenuItem_ID时,如果offers中存在Restaurant_RestaurantID RestaurantIDDelivery等于RestaurantID,我需要以某种方式检查{ {1}}与表格相关联。

我不知道我是否可以在这里使用外键,因为表格不是“相邻”..

我想到的是in_deliveryRestaurant Deliveryoffers和{{1}}都是外键。然后我可以在{{1}}中找到它。还有更好的方法吗?

感谢您的帮助

2 个答案:

答案 0 :(得分:2)

您可以通过以下更改强制执行约束:

  1. restaurant_id
  2. 中添加in_delivery
  3. delivery (delivery_id, restaurant_id)上添加一个唯一约束(需要3。)
  4. 将外键从in_delivery -> delivery更改为指向(delivery_id, restaurant_id)
  5. 将外键从in_delivery -> menu_item更改为in_delivery -> offers

答案 1 :(得分:0)

或者,您可以使用触发器来检查约束:

SQL Fiddle

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 )