如何创建正确的触发器而不是插入或更新?甲骨文。扳机。 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;
/
“INSERT INTO sales”语句的 VALUES 中缺少冒号:
id_user = :user_new,
id_sw = :sw_new,
您说创建触发器时出错。但是如果我试图复制你的问题,我不能,因为 Software
table 的定义无效。首先,外键引用了您的示例中不存在的 table 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_date
或 total_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 example,您可以使用它来确保您拥有的是可重现的测试用例。
帮助创建不可更新视图的触发器。
表格看起来像这样。
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;
/
“INSERT INTO sales”语句的 VALUES 中缺少冒号:
id_user = :user_new, id_sw = :sw_new,
您说创建触发器时出错。但是如果我试图复制你的问题,我不能,因为 Software
table 的定义无效。首先,外键引用了您的示例中不存在的 table 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_date
或 total_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 example,您可以使用它来确保您拥有的是可重现的测试用例。