PL/SQL Challenge 每日一题:2014-1-21 用FORALL和BULK COLLECT批量处理

[复制链接]
查看11 | 回复6 | 2008-9-15 01:28:12 | 显示全部楼层 |阅读模式
最先答对且答案未经编辑的puber将获得纪念章一枚(答案不可编辑但可发新贴补充或纠正),其他会员如果提供有价值的分析、讨论也可获得纪念章一枚。
以往旧题索引:
http://www.itpub.net/forum.php?m ... eid&typeid=1808
http://www.itpub.net/thread-1499223-1-1.html
原始出处:
http://www.plsqlchallenge.com/
作者:Steven Feuerstein
运行环境:SQLPLUS, SERVEROUTPUT已打开
注:本题给出答案时候要求给予简要说明才能得到奖品
我创建了一张表并填入数据:
CREATE TABLE plch_worms
(
worm_name VARCHAR2 (100),
lives_inVARCHAR2 (100)
)
/
BEGIN
INSERT INTO plch_worms
VALUES ('Spaceworm', 'Jupiter');
INSERT INTO plch_worms
VALUES ('Shipworm', 'Ocean');
INSERT INTO plch_worms
VALUES ('Earworm', 'Ear');
INSERT INTO plch_worms
VALUES ('Earthworm', 'Dirt');
COMMIT;
END;
/
然后我写了下列不完整的代码块:
DECLARE
CURSOR worms_cur
IS
SELECT *

FROM plch_worms
ORDER BY worm_name DESC;
TYPE worms_t IS TABLE OF worms_cur%ROWTYPE;
l_worms worms_t;
BEGIN
/*CODE*/
CLOSE worms_cur;
END;
/
哪些选项可用来取代/*CODE*/注释,使得代码块执行之后会显示下列文本:
Jupiter
Ocean
Ear
Dirt
(A)
OPEN worms_cur;
LOOP
FETCH worms_cur BULK COLLECT INTO l_worms;
FOR indx IN 1 .. l_worms.COUNT
LOOP
DBMS_OUTPUT.put_line (l_worms (indx).lives_in);
END LOOP;
EXIT WHEN worms_cur%NOTFOUND;
END LOOP;
(B)
OPEN worms_cur;
FETCH worms_cur BULK COLLECT INTO l_worms;
FOR indx IN 1 .. l_worms.COUNT
LOOP
DBMS_OUTPUT.put_line (l_worms (indx).lives_in);
END LOOP;
(C)
OPEN worms_cur;
FETCH worms_cur BULK COLLECT INTO l_worms LIMIT 100;
FOR indx IN 1 .. l_worms.COUNT
LOOP
DBMS_OUTPUT.put_line (l_worms (indx).lives_in);
END LOOP;
(D)
OPEN worms_cur;
LOOP
FETCH worms_cur BULK COLLECT INTO l_worms LIMIT 3;
FOR indx IN 1 .. l_worms.COUNT
LOOP
DBMS_OUTPUT.put_line (l_worms (indx).lives_in);
END LOOP;
EXIT WHEN worms_cur%NOTFOUND;
END LOOP;

回复

使用道具 举报

千问 | 2008-9-15 01:28:12 | 显示全部楼层
除D以外都是对的吧
回复

使用道具 举报

千问 | 2008-9-15 01:28:12 | 显示全部楼层
答案:A,B,C,D
回复

使用道具 举报

千问 | 2008-9-15 01:28:12 | 显示全部楼层
A,D性质一样,只不过D里限制了一次批量读取的记录数,整个程序块要循环2次。
B,C性质一样,B一次性读取所有记录,C限制为100条。
D是最标准的批量操作块。


回复

使用道具 举报

千问 | 2008-9-15 01:28:12 | 显示全部楼层
都正确吧。D应该是循环取,每次取3个。所以答案也正确
回复

使用道具 举报

千问 | 2008-9-15 01:28:12 | 显示全部楼层
答案ABCD,4楼答对了。
A: (不推荐)
这样能行,但是这是写得很糟糕的代码。我将FETCH-BULK放在一个循环里,但是没有包含LIMIT子句。结果,这个循环永远总是只FETCH一次,每次取所有的数据,然后就终止。这不会有什么问题,但是假如你的表有很多数据,这就可能引发会话的内存错误。
B: (不推荐)
在这个选项中,我弃用了循环。只是打开,获取所有数据,然后遍历数组的所有内容。
这比选项A好点,因为选项A用了一个“假”循环。然而,假如你的表有很多数据,这个选项仍然可能引发会话的内存错误。
并且,如果你想用这种未加限制的循环(指FETCH...BULK COLLECT没有带LIMIT子句),也可以进一步简化(指用隐式游标SELECT INTO代替显式游标):
DECLARE
TYPE worms_t IS TABLE OF plch_worms%ROWTYPE;
l_worms worms_t;
BEGIN
SELECT *
BULK COLLECT INTO l_worms
FROM plch_worms
ORDER BY worm_name DESC;
FOR indx IN 1 .. l_worms.COUNT
LOOP
DBMS_OUTPUT.put_line (l_worms (indx).lives_in);
END LOOP;
END;
/

C: (不推荐)
这又是一个正确而不理想的答案。我没有用循环,但却用了一个LIMIT子句,设置为100。这意味着如果表里有超过100行数据,它们不会被这个代码全部处理。你应该在循环中使用LIMIT子句。

D: (推荐)
啊!终于看到了各种元素的最佳组合:
一个隐式游标的声明
打开游标之后的循环
带有LIMIT子句的FETCH
当所有行都取出并处理之后终止循环(这就是为什么要把%NOTFOUND检查放在循环底部)

回复

使用道具 举报

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

回复

使用道具 举报

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

本版积分规则

主题

0

回帖

4882万

积分

论坛元老

Rank: 8Rank: 8

积分
48824836
热门排行