【问题标题】:Error with variable names when creating an update trigger创建更新触发器时变量名出错
【发布时间】:2017-04-26 14:13:07
【问题描述】:

我正在尝试创建一个触发器,该触发器允许输入大小为 small-large 的衣服,但触发器会根据插入内容将大小更改为 S M 或 L。

我的 if 语句出现错误的绑定变量错误,我不知道为什么,因为它与我的 Products 表中的列名相同。

产品表:

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

尺寸触发:

create or replace TRIGGER sizeTrigger
BEFORE INSERT OR UPDATE
   ON PRODUCTS
BEGIN
   --smalls--
    IF :NEW.product_size = 's' THEN
    ::NEW.PRODUCT_SIZE := 'S';
    elsif ::NEW.PRODUCT_SIZE = 'S' THEN
       ::NEW.product_size := 'S';
     elsif ::NEW.PRODUCT_SIZE = 'small'THEN
       ::NEW.product_size := 'S';
       elsif ::NEW.PRODUCT_SIZE = 'SMALL' THEN
       ::NEW.product_size := 'S';
    --MEDIUM--
    elsif ::NEW.PRODUCT_SIZE = 'm' THEN
       ::NEW.product_size := 'M';
    elsif ::NEW.PRODUCT_SIZE = 'm' THEN
       ::NEW.product_size := 'M';
    elsif ::NEW.PRODUCT_SIZE = 'medium' THEN
       ::NEW.product_size := 'M';
        elsif ::NEW.PRODUCT_SIZE = 'MEDIUM' THEN
       ::NEW.product_size := 'M';
     --large
      elsif ::NEW.PRODUCT_SIZE = 'l' THEN
       ::NEW.product_size := 'L';
    elsif ::NEW.PRODUCT_SIZE = 'L' THEN
       ::NEW.product_size := 'L';
    elsif ::NEW.PRODUCT_SIZE = 'large' THEN
       ::NEW.product_size := 'L';
        elsif ::NEW.PRODUCT_SIZE = 'LARGE' THEN
       ::NEW.product_size := 'L';
      else
          raise exception_error;        
        END IF;
EXCEPTION
   WHEN exception_error THEN
    DBMS_OUTPUT.PUT_LINE('Size must be "s,m,l,small, medium, large");
END;

【问题讨论】:

  • 去掉所有列定义周围的双引号。

标签: oracle plsql triggers


【解决方案1】:

在现实生活中,我们的目标是使用检查约束来强制执行业务规则。

alter table products
    add constraint check_product_size
       check (product_size in ('S', 'M', 'L'));

我希望应用程序为用户提供有效尺寸的选择;如果他们输入的数据在查询时被神秘地更改或丢失,人们会感到困惑。但是如果你想这样做,这里是最简单的触发器(结合上面的检查约束):

create or replace trigger sizetrigger
before insert or update
   on products
   for each row
begin
   :new.product_size := upper(substr(:new.product_size,1,1));
end; 

【讨论】:

    【解决方案2】:

    下面是工作触发器。我稍微简化了逻辑。

    create or replace TRIGGER sizeTrigger
    BEFORE INSERT OR UPDATE
       ON PRODUCTS
       FOR EACH ROW
    DECLARE
      exception_error       EXCEPTION;
    BEGIN
       IF upper(:NEW.product_size)  in ('S','SMALL') THEN :NEW.product_size :='S';
       ELSIF upper(:NEW.product_size)  in ('M','MEDIUM') THEN :NEW.product_size  :='M';
       ELSIF upper(:NEW.product_size)  in ('L','LARGE') THEN :NEW.product_size  :='L';
       ELSE
         raise exception_error; 
       END IF;
    EXCEPTION
       WHEN exception_error THEN
        DBMS_OUTPUT.PUT_LINE('Size must be "s,m,l,small, medium, large"');
       RAISE;
    END;
    

    【讨论】:

    • 嘿,这符合要求,你能解释一下我做错了什么吗?我知道我有双'::'
    • 1) 每一行都没有
    • 2) 在 put_line 调用中未关闭字符串 3) ::NEW 而不是 :NEW
    • 有趣的 idk 我写的时候怎么错过了,非常感谢!
    • 刚刚对其进行了测试,它在大多数情况下都可以正常工作,但它允许通过此插入:INSERT INTO PRODUCTS (pid, product_name, quantity, product_size, product_value) Values(2, 'Product 2', 3, '非常大', 51.00);
    【解决方案3】:

    :new 使用单个: 而不是::

    create or replace TRIGGER sizeTrigger
    BEFORE INSERT OR UPDATE
       ON PRODUCTS FOR EACH ROW
    BEGIN
       --smalls--
        IF :NEW.product_size = 's' THEN
        :NEW.PRODUCT_SIZE := 'S';
        elsif :NEW.PRODUCT_SIZE = 'S' THEN
           :NEW.product_size := 'S';
         elsif :NEW.PRODUCT_SIZE = 'small'THEN
           :NEW.product_size := 'S';
           elsif :NEW.PRODUCT_SIZE = 'SMALL' THEN
           :NEW.product_size := 'S';
        --MEDIUM--
        elsif :NEW.PRODUCT_SIZE = 'm' THEN
           :NEW.product_size := 'M';
        elsif :NEW.PRODUCT_SIZE = 'm' THEN
           :NEW.product_size := 'M';
        elsif :NEW.PRODUCT_SIZE = 'medium' THEN
           :NEW.product_size := 'M';
            elsif :NEW.PRODUCT_SIZE = 'MEDIUM' THEN
           :NEW.product_size := 'M';
         --large
          elsif :NEW.PRODUCT_SIZE = 'l' THEN
           :NEW.product_size := 'L';
        elsif :NEW.PRODUCT_SIZE = 'L' THEN
           :NEW.product_size := 'L';
        elsif :NEW.PRODUCT_SIZE = 'large' THEN
           :NEW.product_size := 'L';
            elsif :NEW.PRODUCT_SIZE = 'LARGE' THEN
           :NEW.product_size := 'L';
          else
              raise exception_error;        
            END IF;
    EXCEPTION
       WHEN exception_error THEN
        DBMS_OUTPUT.PUT_LINE('Size must be "s,m,l,small, medium, large"');
    END;
    

    我也会重构你的代码。而不是这么长的elsif 级联,您可以拥有:

    if upper(:NEW.PRODUCT_SIZE) in ('S', 'SMALL') then :NEW.product_size := 'S';
    if upper(:NEW.PRODUCT_SIZE) in ('M', 'MEDIUM') then :NEW.product_size := 'M';
    if upper(:NEW.PRODUCT_SIZE) in ('L', 'LARGE') then :NEW.product_size := 'L';
    

    所以最终版本是:

    create or replace TRIGGER sizeTrigger
    BEFORE INSERT OR UPDATE
       ON PRODUCTS FOR EACH ROW
    BEGIN
          if upper(:NEW.PRODUCT_SIZE) in ('S', 'SMALL') then :NEW.product_size := 'S';
          elsif upper(:NEW.PRODUCT_SIZE) in ('M', 'MEDIUM') then :NEW.product_size := 'M';
          elsif upper(:NEW.PRODUCT_SIZE) in ('L', 'LARGE') then :NEW.product_size := 'L';
          else
              raise exception_error;        
          END IF;
    EXCEPTION
       WHEN exception_error THEN
        DBMS_OUTPUT.PUT_LINE('Size must be "s,m,l,small, medium, large"');
    END;
    

    【讨论】:

    • 我认为这有所帮助,但我仍然遇到那个糟糕的绑定变量错误 (PLS-00049) 和编译器错误 ORA-04082:表级触发器中不允许新旧引用
    • @nagel9 立即尝试FOR EACH ROW 已添加
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-02-09
    • 1970-01-01
    • 1970-01-01
    • 2021-07-14
    • 1970-01-01
    相关资源
    最近更新 更多