繁体   English   中英

如何创建正确的触发器而不是插入或更新? ORACLE。 扳机。 pl/sql

[英]How to create the correct trigger instead of insert or update? ORACLE. Trigger. pl/sql

帮助为不可更新的视图创建触发器。

桌子看起来像这样。

 CREATE TABLE Users(id_user INTEGER GENERATED ALWAYS AS IDENTITY(START with 1 INCREMENT by 1 NOCACHE) PRIMARY KEY,
                surname VARCHAR2(30) NOT NULL,
                name VARCHAR2(30) NOT NULL,
                patronymic VARCHAR2(30) NULL,
                tel_no VARCHAR2(17) NOT NULL,
              
                CONSTRAINT ch_telno_users
                           CHECK(REGEXP_LIKE(tel_no, '^\+375\(\d{2}\)\d{3}-\d{2}-\d{2}$')),
                CONSTRAINT uni_telno_users
                           UNIQUE(tel_no)
                 );


CREATE TABLE Software(id_sw INTEGER GENERATED ALWAYS AS IDENTITY(START with 1 INCREMENT by 1 NOCACHE) PRIMARY KEY,
                  name_sw VARCHAR2(40) NOT NULL,
                  version VARCHAR2(10) NULL,
                  license_period VARCHAR2(10) NOT NULL,
                  id_mfr INTEGER NOT NULL,
                  release_date DATE NOT NULL,
                  price NUMBER(9,2),
                  total_amount INTEGER NOT NULL,
                CONSTRAINT id_mfr_fk
                           FOREIGN KEY(id_mfr)
                           REFERENCES Manufacturer,           
                  );

    CREATE SYNONYM sw for Software;


CREATE TABLE Sales(id_sale INTEGER GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
               id_user INTEGER NOT NULL,
               id_sw INTEGER NOT NULL,
               quantity INTEGER NOT NULL,
               total_cost NUMBER(9,2),
               order_date DATE NOT NULL CHECK (order_date >= to_date('01/01/2019', 'dd/mm/yyyy')),
               expiration_date DATE NOT NULL,
             CONSTRAINT id_user_fk
                        FOREIGN KEY(id_user)
                        REFERENCES Users,
             CONSTRAINT id_sw_fk
                        FOREIGN KEY(id_sw)
                        REFERENCES Software
            );

视图本身看起来像这样

    CREATE OR REPLACE VIEW SalesView AS
    SELECT Sales.id_sale,sw.name_sw||' '||sw.version sw_full_name,        
    Users.surname||' '||Users.name||' '||Users.patronymic user_full_name,  
    sales.quantity,         sales.order_date
    FROM sw INNER JOIN (Users INNER JOIN Sales ON Sales.id_user = Users.id_user)  ON sw.id_sw = sales.id_sw;

我试图创建这样的触发器。 但由于某种原因,它没有被创建。(第 86 行错误:PL/SQL:SQL 语句被忽略第 94 行错误:PL/SQL:ORA-00917:缺少逗号)

在我看来,我走得很艰难。 帮助修复此代码。

    CREATE OR REPLACE TRIGGER sales_view_instead_of_trig INSTEAD OF
    UPDATE OR INSERT ON salesview
    FOR EACH ROW
      DECLARE
      sw_new        sw.id_sw%TYPE;
      user_new      Users2.id_user%TYPE;
      check_excep_sw   VARCHAR2(51);
      check_excep_user VARCHAR2(92);
    BEGIN
        IF updating THEN --* update
    IF :new.sw_full_name != :old.sw_full_name THEN
        SELECT
            sw.name_sw||' '||sw.version
        INTO check_excep_sw
        FROM
            sw
        WHERE
            sw.name_sw||' '||sw.version = :new.sw_full_name;
        SELECT
            id_sw
        INTO sw_new
        FROM
            sw
        WHERE
            sw.name_sw||' '||sw.version = :new.sw_full_name;
      ELSE
        SELECT
            id_sw
        INTO sw_new
        FROM
            sw
        WHERE
            sw.name_sw||' '||sw.version = :old.sw_full_name;
       END IF;
       IF :new.user_full_name != :old.user_full_name THEN
        SELECT
            Users2.surname||' '||Users2.name||' '||Users2.patronymic
        INTO check_excep_user
        FROM
            Users2
        WHERE
            Users2.surname||' '||Users2.name||' '||Users2.patronymic = :new.user_full_name;
        SELECT
            id_user
        INTO user_new
        FROM
            Users2
        WHERE
            Users2.surname||' '||Users2.name||' '||Users2.patronymic = :new.user_full_name;
       ELSE
        SELECT
            id_user
        INTO user_new
        FROM
            Users2
        WHERE
            Users2.surname||' '||Users2.name||' '||Users2.patronymic = :old.user_full_name;
        END IF;
       UPDATE sales
       SET
        id_user = user_new,
        id_sw = sw_new,
        quantity = :new.quantity,
        order_date = :new.order_date,
        expiration_date = :new.expiration_date,
        total_cost = :new.total_cost
    WHERE
        id_sale = :old.id_sale;
   END IF;
    IF inserting THEN --* insert
   SELECT sw.name_sw||' '||sw.version INTO check_excep_sw
        FROM sw
        WHERE sw.name_sw||' '||sw.version = :new.sw_full_name;
        SELECT id_sw
        INTO sw_new
        FROM sw
        WHERE sw.name_sw||' '||sw.version = :new.sw_full_name;
    SELECT
        Users2.surname||' '||Users2.name||' '||Users2.patronymic
    INTO check_excep_user
    FROM
        Users2
    WHERE
        Users2.surname||' '||Users2.name||' '||Users2.patronymic = :new.user_full_name;
     SELECT id_user
        INTO user_new
        FROM Users2
        WHERE Users2.surname||' '||Users2.name||' '||Users2.patronymic = :new.user_full_name;
    INSERT INTO sales(
        id_user,
        id_sw,
        quantity,
        order_date,
        expiration_date,
        total_cost
     ) VALUES (
        id_user = user_new,
        id_sw = sw_new,
        quantity = :new.quantity,
        order_date = :new.order_date,
        expiration_date = :new.expiration_date,
        total_cost = :new.total_cost
     );
        END IF;
    EXCEPTION
        WHEN no_data_found THEN
    dbms_output.put_line('-------------------------------------------');
    dbms_output.put_line('| ERROR!   |');
    dbms_output.put_line('-------------------------------------------');
    END;
    /

您说创建触发器时出错。 但是,如果我尝试复制您的问题,我不能,因为Software表的定义无效。 首先,外键引用了您的示例中不存在的表Manufacturer 其次,外键约束定义的末尾有一个额外的逗号。

如果我完全删除外键约束

CREATE TABLE Software(id_sw INTEGER GENERATED ALWAYS AS IDENTITY(START with 1 INCREMENT by 1 NOCACHE) PRIMARY KEY,
                  name_sw VARCHAR2(40) NOT NULL,
                  version VARCHAR2(10) NULL,
                  license_period VARCHAR2(10) NOT NULL,
                  id_mfr INTEGER NOT NULL,
                  release_date DATE NOT NULL,
                  price NUMBER(9,2),
                  total_amount INTEGER NOT NULL
                  );

这允许脚本尽可能地尝试创建触发器。 此时,您将收到错误,包括(但不限于)您提到的 ORA-00917 错误。

Errors: TRIGGER SALES_VIEW_INSTEAD_OF_TRIG
Line/Col: 62/27 PLS-00049: bad bind variable 'NEW.EXPIRATION_DATE'
Line/Col: 63/22 PLS-00049: bad bind variable 'NEW.TOTAL_COST'
Line/Col: 86/5 PL/SQL: SQL Statement ignored
Line/Col: 94/17 PL/SQL: ORA-00917: missing comma
Line/Col: 98/27 PLS-00049: bad bind variable 'NEW.EXPIRATION_DATE'
Line/Col: 99/22 PLS-00049: bad bind variable 'NEW.TOTAL_COST'

PLS-00049: bad bind variable错误发生是因为视图定义中没有名为expiration_datetotal_cost的列。 因此,不存在:new.expiration_date:new.total_cost这样的东西,因为针对视图的 DML 无法为这些列指定值。 我不知道你想如何处理——要么省略值,提供默认值,从其他地方读取值,将列添加到视图中,然后在 DML 中针对视图提供它们, expiration_date 。被定义为not null似乎限制了您的选择。

如果您查看触发器的第 86 行,您将看到此语句

INSERT INTO sales(
        id_user,
        id_sw,
        quantity,
        order_date,
        expiration_date,
        total_cost
     ) VALUES (
        id_user = user_new,
        id_sw = sw_new,
        quantity = :new.quantity,
        order_date = :new.order_date,
        expiration_date = :new.expiration_date,
        total_cost = :new.total_cost
     );

这在语法上无效。

INSERT INTO sales(
        id_user,
        id_sw,
        quantity,
        order_date,
        expiration_date,
        total_cost
     ) VALUES (
        user_new,
        sw_new,
        :new.quantity,
        :new.order_date,
        :new.expiration_date,
        :new.total_cost
     );

如果:new.expiration_date:new.total_cost是有效标识符,则有效。 但是,如上所述,它们无效。 而且,您希望插入的值是什么并不明显。

这是一个liveSQL 示例,您可以使用它来确保您拥有的是可重现的测试用例。

“INSERT INTO sales”语句的 VALUES 上缺少冒号:

 id_user =:user_new, id_sw =:sw_new,

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM