PL/SQL Challenge 每日一题:2020-5-25 insert触发器

[复制链接]
查看11 | 回复3 | 2008-9-15 01:28:12 | 显示全部楼层 |阅读模式
最先答对且答案未经编辑的puber将获得纪念章一枚(答案不可编辑但可发新贴补充或纠正),其他会员如果提供有价值的分析、讨论也可获得纪念章一枚。
每两周的优胜者可获得itpub奖励的技术图书一本。
以往旧题索引:
http://www.itpub.net/forum.php?m ... eid&typeid=1808
原始出处:
http://www.plsqlchallenge.com/
作者:Steven Feuerstein
运行环境:SQLPLUS, SERVEROUTPUT已打开, 最低版本要求:11.2
注:本题给出答案时候要求给予简要说明才能得到奖品
我想了想,是时候给自己列一个清单了,必须要有哪些东西才能保持安全和健康。于是,我创建了一个表,并插入了一行。然后我创建了一个触发器:

CREATE TABLE qz_must_haves
(
id INTEGER,
nm VARCHAR2 (100)
)
/
BEGIN
INSERT INTO qz_must_haves (id, nm)
VALUES (1, 'Mask');
END;
/
CREATE OR REPLACE TRIGGER qz_must_haves_bi
BEFORE INSERT
ON qz_must_haves
FOR EACH ROW
DECLARE
l_count NUMBER;
BEGIN
SELECT COUNT (*) INTO l_count FROM qz_must_haves;
IF l_count = 0
THEN
raise_application_error (-20000,

'"Must have" means .... you *must* have it!');
END IF;
END;
/
CREATE OR REPLACE PROCEDURE qz_check_for_success
IS
l_count NUMBER;
BEGIN
SELECT COUNT (*) INTO l_count FROM qz_must_haves;
IF l_count > 1
THEN
DBMS_OUTPUT.put_line ('Success :-)');
ELSE
DBMS_OUTPUT.put_line ('Failure :-(');
END IF;
END;
/
但是我要的不只是一个口罩。所以我需要插入更多的行。
哪些选项在执行之后,我再运行如下的代码块,我会看到 "Success :-)" ?
BEGIN
qz_check_for_success;
END;
/
(A)
BEGIN
INSERT INTO qz_must_haves (id, nm)
VALUES (1000, 'Soap');
END;
/
(B)
BEGIN
INSERT INTO qz_must_haves (id, nm)
SELECT 1000, 'Soap' FROM DUAL;
END;
/
(C)
DECLARE
TYPE mh_t IS TABLE OF qz_must_haves%ROWTYPE
INDEX BY PLS_INTEGER;
l_must_haves mh_t;
BEGIN
l_must_haves (1).id := 1000;
l_must_haves (1).nm := 'Soap';
FORALL indx IN 1 .. l_must_haves.COUNT
INSERT INTO qz_must_haves (id, nm)
VALUES (l_must_haves (indx).id, l_must_haves (indx).nm);
END;
/
(D)
INSERT ALL
INTO qz_must_haves (id, nm)
SELECT 1000, 'Soap' FROM DUAL
/

回复

使用道具 举报

千问 | 2008-9-15 01:28:12 | 显示全部楼层
答案AC
A) 正确,首先insert一条记录,不提交,此时再创建触发器和存储过程。
直接通过insert into录入表数据,正确
B) 错误,ORA-04091: 表 QZ_MUST_HAVES 发生了变化, 触发器/函数不能读它
insert select语句,触发器是before insert,此时这个语句数据没有录入到表
因为在创建触发器之前,有一个未提交的insert语句,会去读这个未完成的事务,故报错
可以通过加PRAGMA AUTONOMOUS_TRANSACTION 自治事务来解决这个问题
不过加了自治事务,程序逻辑可能也会发生变化,这个需要注意。
C) 正确,直接通过forall 语句进行insert。
D) 错误,原因同B
回复

使用道具 举报

千问 | 2008-9-15 01:28:12 | 显示全部楼层

答案:AC
A: 单条INSERT 语句
B: ORA-04091: table QZ_MUST_HAVES is mutating, trigger/function may not see it
触发器尝试查看正在被语句修改的表,而该语句正触发触发器
C: FORALL 用集合插入,但也被视为单条语句
D: ORA-04091: table QZ_MUST_HAVES is mutating, trigger/function may not see it

回复

使用道具 举报

千问 | 2008-9-15 01:28:12 | 显示全部楼层
答案AC, 2楼得奖。
A:
我只插入了一行。用这个语法,不可能通过这个语句插入多于一条记录。所以Oracle数据库不需要担心会引起表变异,于是插入成功。
B:
即使我的INSERT-SELECT只插入了一条记录,也有可能插入更多的记录,所以当第一条记录被插入时,变异表触发错误被抛出。
C:
FORALL-INSERT的处理方式和INSERT-SELECT差不多。但变异表错误只在第二行时触发。下面这个例子的代码块确实会报错:
"ORA-04091: table QZ_MUST_HAVES is mutating, trigger/function may not see it"
DECLARE
TYPE mh_t IS TABLE OF qz_must_haves%ROWTYPE
INDEX BY PLS_INTEGER;
l_must_haves mh_t;
BEGIN
l_must_haves (1).id := 1000;
l_must_haves (1).nm := 'Soap';
l_must_haves (2).id := 10009;
l_must_haves (2).nm := 'Soapx';
FORALL indx IN 1 .. l_must_haves.COUNT
INSERT INTO qz_must_haves (id, nm)
VALUES (l_must_haves (indx).id, l_must_haves (indx).nm);
END;
/
D:
INSERT-ALL-SELECT和INSERT-SELECT有同样的问题,无论你有多少不同的INTO子句,都会出现变异表触发器错误。
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

主题

0

回帖

4882万

积分

论坛元老

Rank: 8Rank: 8

积分
48824836
热门排行