PL/SQL Challenge 每日一题:2015-8-6 PL/SQL的事务处理

[复制链接]
查看11 | 回复5 | 2008-9-15 01:28:12 | 显示全部楼层 |阅读模式
最先答对且答案未经编辑的puber将获得纪念章一枚(答案不可编辑但可发新贴补充或纠正),其他会员如果提供有价值的分析、讨论也可获得纪念章一枚。
以往旧题索引:
http://www.itpub.net/forum.php?m ... eid&typeid=1808
原始出处:
http://www.plsqlchallenge.com/
作者:Steven Feuerstein
运行环境:SQLPLUS, SERVEROUTPUT已打开
注:本题给出答案时候要求给予简要说明才能得到奖品
我执行了下列语句:
CREATE TABLE plch_names (my_name VARCHAR2 (100) UNIQUE)
/
BEGIN
FOR indx IN 1 .. 20
LOOP
INSERT INTO plch_names (my_name)
VALUES ('Steven' || indx);
END LOOP;
COMMIT;
END;
/
哪些选项会使得下列代码块执行之后,屏幕上会显示 "21" ?
DECLARE
l_count PLS_INTEGER;
BEGIN
plch_add_name ('Steven1');
SELECT COUNT (*) INTO l_count FROM plch_names;
DBMS_OUTPUT.put_line (l_count);
END;
/
(A)
CREATE OR REPLACE PROCEDURE plch_add_name (
new_name_in IN VARCHAR2)
AUTHID DEFINER
IS
BEGIN
INSERT INTO plch_names (my_name)
VALUES (new_name_in);
END;
/

(B)
CREATE OR REPLACE PROCEDURE plch_add_name (
new_name_in IN VARCHAR2)
AUTHID DEFINER
IS
BEGIN
INSERT INTO plch_names (my_name)
VALUES (new_name_in);
EXCEPTION
WHEN DUP_VAL_ON_INDEX
THEN
INSERT INTO plch_names (my_name)
VALUES (new_name_in || '1');
END;
/
(C)
CREATE OR REPLACE PROCEDURE plch_add_name (
new_name_in IN VARCHAR2)
AUTHID DEFINER
IS
l_name plch_names.my_name%TYPE := new_name_in;
l_dummyCHAR (1);
l_all_done BOOLEAN := FALSE;
BEGIN
LOOP
BEGIN
SELECT 'x'
INTO l_dummy
FROM plch_names

WHERE my_name = l_name;
l_name := l_name || '1';
EXCEPTION
WHEN NO_DATA_FOUND
THEN

INSERT INTO plch_names (my_name)

VALUES (l_name);

l_all_done := TRUE;
END;
EXIT WHEN l_all_done;
END LOOP;
END;
/
(D)
CREATE OR REPLACE PROCEDURE plch_add_name (
new_name_in IN VARCHAR2)
AUTHID DEFINER
IS
l_nameplch_names.my_name%TYPE := new_name_in;
l_dummy CHAR (1);
BEGIN
LOOP
BEGIN
SELECT 'x'
INTO l_dummy
FROM plch_names

WHERE my_name = l_name;
l_name := l_name || '1';
EXCEPTION
WHEN NO_DATA_FOUND
THEN

INSERT INTO plch_names (my_name)

VALUES (l_name);
END;
EXIT WHEN SQL%ROWCOUNT = 1;
END LOOP;
END;
/
(E)
CREATE OR REPLACE PROCEDURE plch_add_name (
new_name_in IN VARCHAR2)
AUTHID DEFINER
IS
l_name plch_names.my_name%TYPE := new_name_in;
BEGIN
LOOP
BEGIN
INSERT INTO plch_names (my_name)

VALUES (l_name);
EXIT;
EXCEPTION
WHEN DUP_VAL_ON_INDEX
THEN

l_name := l_name || '1';
END;
END LOOP;
END;
/
(F)
CREATE OR REPLACE PROCEDURE plch_add_name (
new_name_in IN VARCHAR2)
AUTHID DEFINER
IS
l_name plch_names.my_name%TYPE := new_name_in;
l_dummyCHAR (1);
l_all_done BOOLEAN := FALSE;
BEGIN
LOOP
BEGIN
SELECT 'x'
INTO l_dummy
FROM plch_names

WHERE my_name = new_name_in;
l_name := l_name || '1';
EXCEPTION
WHEN NO_DATA_FOUND
THEN

INSERT INTO plch_names (my_name)

VALUES (l_name);

l_all_done := TRUE;
END;
EXIT WHEN l_all_done;
END LOOP;
END;
/


回复

使用道具 举报

千问 | 2008-9-15 01:28:12 | 显示全部楼层
A.Steven1违反唯一约束
B.Steven11照样违反
C.OK.循环捕获异常,直到表中不存在这个之,跳出循环。
D.执行完SELECT 'x'
INTO l_dummy
FROM plch_names

WHERE my_name = l_name; 这句sql%rowcount就已经是1了。直接跳出循环。
E.OK.循环报错,直到执行成功,就进入exit
F.偷偷的换了一个变量,看看你眼力,我是说哪里不对,这个跳不出循环啊。
我选CE
回复

使用道具 举报

千问 | 2008-9-15 01:28:12 | 显示全部楼层
A:报错违反了一意制約
B:同理和B一样,都是插入同一个数据,一样会出现一一制约,只不过和A相比是先走主键不为空
C:这个比较隐晦,这个是这么做的,先看看这里面有没有数据,有数据就在字符串后面拼个1再看有没有数据,直到没数据再往里面插,这个类似一个MERGE INTO
D:这个和C起初看起来一样,但是最后有个SQL%ROWCOUNT=1,这就是只要最后有数据就直接退出了,但是这有种情况会往里面插入数据,是你要查询的数据不存在,或者表为空
E:这个就是拼字符串,直到插入不报错就退出,没什么好说的
F:我啥也不说了,这个我看了都好半天了,最后看了2L才发现原来这个变量写错了,你用new_name_in来当检索条件,l_name来赋值,一辈子都挑不出去诶。
答案:CE
回复

使用道具 举报

千问 | 2008-9-15 01:28:12 | 显示全部楼层
DJQTDJ 发表于 2015-8-11 09:17
A:报错违反了一意制約
B:同理和B一样,都是插入同一个数据,一样会出现一一制约,只不过和A相比是先走主键 ...

你写PL/SQL有前途
回复

使用道具 举报

千问 | 2008-9-15 01:28:12 | 显示全部楼层
答案 CE, 2楼得奖。
A:
试图插入"Steven1"将会引发DUP_VAL_ON_INDEX异常,因为这个名字已经在表中使用了。这个错误没有被处理,因此数据没有插入,事实上这个块会失败,永远没有机会调用DBMS_OUTPUT.put_line.
B:现在我处理了错误,但是仅仅是重试,在后面追加了“1”。有时候这个方法可行,但此处不行,因为"Steven11"也已经在表中了。
C:我先检查表中是否已经有这个名字。如果有,我在名字后面加个“1”然后重试。如果没有,我执行插入并且强行中断循环。如果你知道通常一个新名字会在表中出现,这个方法就比较有道理。
D:
当心!这个选项检查SQL%ROWCOUNT来判断一个行是否被正确插入(开发者会这么想)。但是如果读取成功的话, SQL%ROWCOUNT仍然返回1,所以循环会过早退出。
E:
看起来不错!我执行了插入。如果它报唯一索引错误,我唤个名字并重试,直至插入不出错。简洁干净,比起“现查询再插入”更好,假设你大部分情况下都不会碰到DUP_VAL_ON_INDEX异常。
F:
这是个死循环,当你不小心拷贝/粘贴就可能碰到这种东西。问题在于WHERE子句仍然引用了new_name_in。这种代码是这样产生的:我开始写的是类似A,B这种简单算法。没有本地变量,只是在where子句引用了参数值。然后我意识到需要多做些事,因此声明了本地变量,从参数初始化,增加了改名字的代码,等等。但是我忘记修改WHERE子句了。呃!

回复

使用道具 举报

千问 | 2008-9-15 01:28:12 | 显示全部楼层
〇〇 发表于 2015-8-11 20:53
你写PL/SQL有前途

但是我已经写够了,真的写够了
回复

使用道具 举报

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

本版积分规则

主题

0

回帖

4882万

积分

论坛元老

Rank: 8Rank: 8

积分
48824836
热门排行