oracle中的触发器允许在找到字段时插入

时间:2016-12-13 21:56:14

标签: oracle plsql triggers

我有三个名为products,customers和reserve_products的表。触发器位于保留产品表中,只有在找到客户ID和产品ID以及产品数量时才允许您插入表中。我遇到sql问题并检查行是否存在。

我的表格如下:
的产品

CREATE TABLE "SNAGEL"."PRODUCTS" 
   (    "PID" NUMBER(6,0), 
    "PRODUCT_NAME" VARCHAR2(255 BYTE), 
    "QUANTITY" NUMBER, 
    "PRICE" NUMBER, 
    "PRODUCT_SIZE" VARCHAR2(255 BYTE), 
    "PRODUCT_VALUE" NUMBER, 
     PRIMARY KEY ("PID")

客户

 CREATE TABLE "SNAGEL"."CUSTOMERS" 
   (    "CID" NUMBER(6,0), 
    "FIRST_NAME" VARCHAR2(30 BYTE), 
    "LAST_NAME" VARCHAR2(30 BYTE), 
    "PHONE_NUMBER" NUMBER, 
     PRIMARY KEY ("CID")

储备产品

我的触发器

CREATE OR REPLACE TRIGGER reserveProductTrigger
    before insert on RESERVE_PRODUCT FOR EACH ROW
DECLARE
  pid products.pid%rowtype;
  pidError exception;
  cid customers.cid%rowtype;
  cidError exception;
  pidSoldout exception;
  productQuantity number;
BEGIN
  select cid from CUSTOMERS 
  where cid = :new.CID;

  select COUNT(pid from products
  where pid = :new.PID;

  select quantity into productQuantity 
  from products
  where pid= :new.pid;

  if cid = null then
    raise cidError;
  elsif pid = null then
    raise pidError;
  elsif productQuantity = 0 then
    raise pidSoldout;
  else
    update products
    set quantity = productQuantity -1
    where pid = pid;
  END IF;
EXCEPTION
  When cidError then
    DBMS_OUTPUT.PUT_LINE('CUSTOMER not found error!');
    RAISE;
  When PidError then
    DBMS_OUTPUT.PUT_LINE('PRODUCT not found error!');
    RAISE;
  When pidSoldout then
    DBMS_OUTPUT.PUT_LINE('product sold out error!');
    RAISE;
END;
/

2 个答案:

答案 0 :(得分:0)

您忘记将select语句中的详细信息存储到为其创建的变量yoiu中。所以试试这个:

CREATE OR REPLACE TRIGGER reserveProductTrigger
    before insert on RESERVE_PRODUCT FOR EACH ROW
DECLARE
  pid products.pid%type;
  pidError exception;
  cid customers.cid%type;
  cidError exception;
  pidSoldout exception;
  productQuantity number;
BEGIN
  BEGIN
    select cid into CID
      from CUSTOMERS 
    where cid = :new.CID;
  EXCEPTION WHEN NO_DATA_FOUND THEN
    raise cidError;
  END;

  BEGIN
    select pid
         , quantity
      INTO PID
         , productQuantity
      from products
    where pid = :new.PID;
  EXCEPTION WHEN NO_DATA_FOUND THEN
    raise pidError;
  END;

  if productQuantity <= 0 then -- If it goes negative you've over
    raise pidSoldout;             -- committed and shouldn't accept either.
  else
    update products
    set quantity = productQuantity -1
    where pid = pid;
  END IF;
EXCEPTION
  When cidError then
    DBMS_OUTPUT.PUT_LINE('CUSTOMER not found error!');
    RAISE;
  When PidError then
    DBMS_OUTPUT.PUT_LINE('PRODUCT not found error!');
    RAISE;
  When pidSoldout then
    DBMS_OUTPUT.PUT_LINE('product sold out error!');
    RAISE;
END;
/

但是,您应该使用参照完整性约束,而不是依靠触发器来检查PID和CID的存在。此外,您可以在产品中的数量列上设置检查约束,要求它为&gt; = 0。

然后你在触发器中唯一需要做的就是减少数量:

CREATE TABLE "PRODUCTS" 
   (    "PID" NUMBER(6,0), 
    "PRODUCT_NAME" VARCHAR2(255 BYTE), 
    "QUANTITY" NUMBER CONSTRAINT PRODUCT_MIN_QUANTITY CHECK (QUANTITY >= 0), -- Add Check constraint here
    "PRICE" NUMBER, 
    "PRODUCT_SIZE" VARCHAR2(255 BYTE), 
    "PRODUCT_VALUE" NUMBER, 
     CONSTRAINT PRODUCTS_PK PRIMARY KEY ("PID") -- Name the PK Constraint
     );

CREATE TABLE "CUSTOMERS" 
   (    "CID" NUMBER(6,0), 
    "FIRST_NAME" VARCHAR2(30 BYTE), 
    "LAST_NAME" VARCHAR2(30 BYTE), 
    "PHONE_NUMBER" NUMBER, 
     CONSTRAINT CUSTOMERS_PK PRIMARY KEY ("CID") -- Name the PK Constraint
     );

create table reserve_product (
  PID NOT NULL CONSTRAINT reserve_product_fk REFERENCES products(PID)  -- Use referential integrity here
, CID NOT NULL CONSTRAINT reserve_product_fk REFERENCES customers(CID) -- and here
)

CREATE OR REPLACE TRIGGER reserveProductTrigger
    before insert on RESERVE_PRODUCT FOR EACH ROW
BEGIN
    update products
    set quantity = quantity -1
    where pid = :new.pid;
END;
/

现在,如果产品或客户分别缺少PID或CID,或者产品记录的数量为0,则会引发相应的异常。

答案 1 :(得分:0)

CREATE OR REPLACE TRIGGER trg_reserve_products
BEFORE INSERT ON reserve_products
FOR EACH ROW
DECLARE
  v_count NUMBER;
  v_p_id NUMBER(6);
  v_c_id NUMBER(6);
  v_p_quantity products.p_quantity%TYPE;
  v_p_name products.p_name%TYPE;
BEGIN
  SELECT COUNT(*)
  INTO v_count
  FROM products
  WHERE p_id = :NEW.p_id;
  IF v_count = 0 THEN
    raise_application_error(-20000 , 'Invalid Product ID.');
  END IF;

  SELECT COUNT(*)
  INTO v_count
  FROM customers
  WHERE c_id = :NEW.c_id;
  IF v_count IS NULL THEN
    raise_application_error(-20000 , 'Invalid Customer ID.');
  END IF; 
  
  SELECT p_quantity, p_name
  INTO v_p_quantity, v_p_name
  FROM products
  WHERE p_id = :NEW.p_id;  
  IF v_p_quantity < 1 THEN
    raise_application_error(-20000 , v_p_name || ' 4 is currently out of stock.');
  END IF; 
  
  UPDATE products
  SET p_quantity = p_quantity - 1
  WHERE p_id = :NEW.p_id;
END trg_reserve_products;

SELECT * FROM products;

INSERT INTO reserve_products VALUES(1, 101, 1);
INSERT INTO reserve_products VALUES(2, 46, 1);
INSERT INTO reserve_products VALUES(3, 46, 2);
INSERT INTO reserve_products VALUES(4, 46, 3);

SELECT * FROM products;

SELECT * FROM reserve_products;