分享
 
 
 

PL/SQL 集合相关功能探讨

王朝mssql·作者佚名  2008-05-31
窄屏简体版  字體: |||超大  

Oracle PL/SQL变得更快、更易于使用,特性集也更加丰富了。Oracle数据库10g通过一系列有益的改进,继续保持了PL/SQL在速度、简单易用性和特性扩展方面的传统优势,这些改进包括:

大大提高了执行速度,这要归功于透明的性能改进,其中包括一个新的优化编译器、更优的集成化本地编译功能,以及帮助解决数字运算应用程序问题的新的数据类型。

FORALL语句更加灵活、更加有用。例如:FORALL现在支持非连续索引。

正则表达式以三个新函数(REGEXP_INSTR、REGEXP_REPLACE和REGEXP_SUBSTR)和用于比较的REGEXP_LIKE运算符的形式用于PL/SQL语言中。(要获得更多信息,参见本期杂志中Jonathan Gennick撰写的《一流的表达式》一文。)

集合得到了改进,包括比较集合是否相同、支持对嵌套表进行集合运算等。

Oracle数据库10g使PL/SQL继续保持其作为Oracle数据库的最高效、最富生产力的编程语言的地位。其在性能方面的大大提升,以及对IEEE算法和正则表达式的支持,如今完全开启了将PL/SQL作为首选语言的新的功能领域。

作为介绍Oracle数据库10g中的PL/SQL系列文章的第一篇,本文将对Oracle数据库10g中与集合相关的一些改进进行探讨。

比较集合

20世纪90年代末期,当我首次对开发人员进行PL/SQL培训的时候,很少有人使用(甚至知道)包(package),而现在,很多人(包括我自己在内)都认为它是任何设计精良的PL/SQL应用程序的基础。如今,打包软件得到了广泛使用。 目前,非常重要但未得到充分利用的PL/SQL特性的前沿领域似乎就是集合的使用了。

集合是Oracle中的数组,集合是一维列表。早在Oracle7中,就已经用到了集合(那时,称作“PL/SQL表”),但其功能及性能却很有限。不过,Oracle后来的各个版本都对集合进行了改进。在Oracle数据库10g中,这些数据结构对于几乎所有的复杂PL/SQL应用程序项目来说都是强有力的、快速的和必不可少的。

Oracle数据库10g对集合的一个要害性改进是能够比较两个集合内容的相同之处(和不同之处)。在Oracle数据库10g之前,你也可以对两个集合进行比较,但必须为此编写一个函数。编写这样的程序时需要考虑数个复杂因素,包括:

必须为正在使用的各个集合类型分别编写程序。即使两个集合中的数据类型相同,但假如它们不是基于完全相同的类型定义的,你都需要使用不同的函数来进行比较。

必须对表的内容进行逐行比较,这就意味着必须进行“全集合扫描”。完成这一任务的代码不是很复杂。但是,这一代码冗长乏味,易于出错,非凡是比较诸如记录、对象或者XMLType等复杂数据类型的集合时更是如此。

你必须决定如何处理NULL。假如两行都包含NULL,那么它们相同吗?Oracle认为:“它们既不是相同,也不是不相同,”但是,你的判定可能会与此不同,你必须编写代码来处理这个问题。

这种复杂性导致你不愿意经常编写这类程序,你甚至会在应用程序中回避编写这类程序。

在Oracle数据库10g中,collcompare.sql文件包含了这类程序的一个示例,该程序是为基于employee表的记录集合而编写的。

假设我在collcompare.sql脚本中安装了emp_coll_pkg.equal函数。我可以按照如下方式来使用它:

DECLARE

dbas emp_coll_pkg.employee_tt;

developers emp_coll_pkg.employee_tt;

BEGIN

populate_lists (dbas, developers);

IF emp_coll_pkg.equal (dbas, developers)

THEN

DBMS_OUTPUT.PUT_LINE (

'Likely a very small IT organization!');

END IF;

END;

这段代码简单明了、可读性好。(你不用再经历编写此类函数的痛苦过程多好啊!)为了让你工作更轻松,Oracle数据库10g现在答应你对两个嵌套表进行“原始”比较(native compare)了。换句话说,你不必再编写任何特定于集合的比较逻辑,而可以直接进行比较,如下所示:

DECLARE

dbas emp_coll_pkg.employee_tt;

developers emp_coll_pkg.employee_tt;

BEGIN

populate_lists (dbas, developers);

IF dbas = developers

THEN

DBMS_OUTPUT.PUT_LINE (

'Likely a very small IT organization!');

END IF;

END;

在这种情况下,集合比较仅适用于嵌套表。

换句话说,你还不能直接比较两个关联数组(过去称作"索引表")或者变长数组的内容。希望Oracle数据库的下一版本会增加关联数组和变长数组的比较功能。

集合理论与Multiset Union运算

SQL语言很久以前就提供了将集合运算(UNION、INTERSECT和MINUS)用于查询结果集的功能。如今在Oracle数据库10g中,你可以对PL/SQL程序中的嵌套表(且仅限于嵌套表)和在关系表中声明为列的嵌套表使用上述功能强大的高级运算符。

现在我们从UNION开始,看看这样做所需的一些语法。

首先,我创建一个模式级别的嵌套表类型:

CREATE OR REPLACE TYPE strings_nt

IS TABLE OF VARCHAR2(100);

/

然后,我定义一个包,在该包中,我创建并填充两个此种类型的嵌套表,每个嵌套表都包含一些我和我父亲最喜欢的东西:

CREATE OR REPLACE PACKAGE favorites_pkg

IS

my_favoritesstrings_nt

:= strings_nt ('CHOCOLATE'

, 'BRUSSEL SPROUTS'

, 'SPIDER ROLL'

);

dad_favorites strings_nt

:= strings_nt ('PICKLED HERRING

, 'POTATOES'

, 'PASTRAMI'

, 'CHOCOLATE'

);

PROCEDURE show_favorites (

title_in IN VARCHAR2

, favs_inIN strings_nt

);

END;

/

在该包中,我还创建了一个用于显示strings_nt 嵌套表内容的过程。下面很快就会用到它。

通过在任意程序外的包中定义这些集合,这些集合在我的对话期间会一直保持不变(保持其状态和值),直到我将更改或删除它们为止。这就是说,现在我可以在包外编写程序来对这些集合的内容进行操作了。

注重,出于介绍集合功能的目的,我对该包进行了简化。在生产应用程序中,你应该时刻注重“隐藏”包主体中的包数据(如同这些集合一样),然后提供过程和函数来治理这些数据。

例如,假设我想把这两个集合合并成一个“我们的最爱”的集合。在Oracle数据库10g出现以前,我必须编写一个将一个集合的内容转移到另一个集合的循环。而现在,我可以依靠MULTISET UNION运算符来实现这一点了,如下所示:

DECLARE

our_favorites

strings_nt := strings_nt ();

BEGIN

our_favorites :=

favorites_pkg.my_favorites

MULTISET UNION

favorites_pkg.dad_favorites;

favorites_pkg.show_favorites (

'ME then DAD', our_favorites);

END;

/

此脚本的输出结果为:

ME then DAD

1 = CHOCOLATE

2 = BRUSSEL SPROUTS

3 = SPIDER ROLL

4 = PICKLED HERRING

5 = POTATOES

6 = PASTRAMI

7 = CHOCOLATE

可以看出,两个嵌套表的值被合并到一起了。而且马上就可以看到,MULTISET UNION运算符不同于SQL UNION运算符(实际上,与SQL的UNION ALL运算符完全相同)。对两个SELECT结果集进行UNION运算时,SQL引擎会自动生成一个惟一的有序结果集。换句话说,假如我的两个嵌套表都是查询,那么UNION将生成这样的结果集:

BRUSSEL SPROUTS

CHOCOLATE

PASTRAMI

PICKLED HERRING

POTATOES

SPIDER ROLL

这些数据是按照字母顺序排列的,且CHOCOLATE仅出现一次。为什么会产生不同的结果呢?因为嵌套表是一种多集合(multiset),mathworld.wolfram.com/Multiset.Html 对其做了如下定义:

“一种类似于集合的对象,在其内部,顺序没有意义,而多重性却具有明确的意义;因此,多集合{1, 2, 3}和{2, 1, 3}是等同的,而{1, 1, 2, 3}和{1, 2, 3}却是不同的。”

Oracle文件中说,嵌套表和变长数组的区别在于嵌套表列中存储的数据不保存其顺序,而在变长数组中存储的数据保存其顺序。在Oracle数据库10g之前,这种区别在PL/SQL中没多大意义。现在,有了集合运算符之后,多集合(或嵌套表)的特性便显得极为重要了。

为了更好地理解嵌套表数据没有顺序,MULTISET UNION也不会对结果嵌套表应用顺序这一特性,请我们来看看面的这个程序块:

DECLARE

our_favorites

strings_nt := strings_nt ();

BEGIN

our_favorites :=

favorites_pkg.dad_favorites

MULTISET UNION

favorites_pkg.my_favorites;

favorites_pkg.show_favorites (

'DAD then ME', our_favorites);

END;

/

与前面的程序块惟一不同的是,我改变了MULTISET UNION运算中嵌套表的顺序。

结果就变为:

DAD then ME

1 = PICKLED HERRING

2 = POTATOES

3 = PASTRAMI

4 = CHOCOLATE

5 = CHOCOLATE

6 = BRUSSEL SPROUTS

7 = SPIDER ROLL

假如你不希望合并之后的嵌套表中出现重复项,那么可

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
2023年上半年GDP全球前十五强
 百态   2023-10-24
美众议院议长启动对拜登的弹劾调查
 百态   2023-09-13
上海、济南、武汉等多地出现不明坠落物
 探索   2023-09-06
印度或要将国名改为“巴拉特”
 百态   2023-09-06
男子为女友送行,买票不登机被捕
 百态   2023-08-20
手机地震预警功能怎么开?
 干货   2023-08-06
女子4年卖2套房花700多万做美容:不但没变美脸,面部还出现变形
 百态   2023-08-04
住户一楼被水淹 还冲来8头猪
 百态   2023-07-31
女子体内爬出大量瓜子状活虫
 百态   2023-07-25
地球连续35年收到神秘规律性信号,网友:不要回答!
 探索   2023-07-21
全球镓价格本周大涨27%
 探索   2023-07-09
钱都流向了那些不缺钱的人,苦都留给了能吃苦的人
 探索   2023-07-02
倩女手游刀客魅者强控制(强混乱强眩晕强睡眠)和对应控制抗性的关系
 百态   2020-08-20
美国5月9日最新疫情:美国确诊人数突破131万
 百态   2020-05-09
荷兰政府宣布将集体辞职
 干货   2020-04-30
倩女幽魂手游师徒任务情义春秋猜成语答案逍遥观:鹏程万里
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案神机营:射石饮羽
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案昆仑山:拔刀相助
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案天工阁:鬼斧神工
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案丝路古道:单枪匹马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:与虎谋皮
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:李代桃僵
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:指鹿为马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:小鸟依人
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:千金买邻
 干货   2019-11-12
 
推荐阅读
 
 
 
>>返回首頁<<
 
靜靜地坐在廢墟上,四周的荒凉一望無際,忽然覺得,淒涼也很美
© 2005- 王朝網路 版權所有