Oracle集合类型
所謂集合是一種類似于列表或者一維數(shù)組的數(shù)據(jù)結(jié)構(gòu)。PL/SQL提供了三種集合類型:關(guān)聯(lián)數(shù)據(jù)組(索引表),嵌套表和VARRAY(可變長(zhǎng)數(shù)組)。
?
1.集合類型
1.1關(guān)聯(lián)數(shù)組
關(guān)聯(lián)數(shù)組(也稱為索引表)是一組鍵值對(duì)。每個(gè)密鑰都是唯一的,并且被用于定位相應(yīng)的值。鍵可以是整數(shù)或字符串。只能用于PL/SQL環(huán)境。
?
1.2嵌套表
從概念上講,嵌套表像一個(gè)元素?cái)?shù)量任意的一維數(shù)組。
在數(shù)據(jù)庫(kù)中,嵌套表是存儲(chǔ)一組值的列類型,數(shù)據(jù)庫(kù)存儲(chǔ)嵌套表的行是沒有特定順序的。當(dāng)你從數(shù)據(jù)中提取嵌套表到PL/SQL變量時(shí),該行給出連續(xù)從1開始的下標(biāo)。通過(guò)這些類似數(shù)組下標(biāo)訪問獨(dú)立的行。
嵌套表不同于數(shù)組的重要方面:
- 數(shù)組需要聲明元素的個(gè)數(shù),而嵌套表不需要。嵌套表的大小可以動(dòng)態(tài)增加。
- 數(shù)組總是密集的,嵌套表剛開始是密集的,但是后面有可能會(huì)變成稀疏的。因?yàn)槟銜?huì)從嵌套表中刪除元素。
?
1.3 可變長(zhǎng)的數(shù)組
可變長(zhǎng)的數(shù)組是一個(gè)VARRAY數(shù)據(jù)類型的集合。當(dāng)你聲明VARRAY類型的時(shí)候,就必須指定同時(shí)指定它能夠包含的最大元素個(gè)數(shù)。VARRAY可以包含可變數(shù)據(jù)的元素,從零到最大值。VARRAY索引有一個(gè)固定定的下限1和一個(gè)可擴(kuò)展的上限。和嵌套表類型一樣的是,它們都可以用于PL/SQL和數(shù)據(jù)庫(kù)。但是和嵌套表不一樣的是,在向VARRAY中保存數(shù)據(jù)或者提取數(shù)據(jù)時(shí),它的元素是有序的。
?
2.聲明集合類型
在使用一個(gè)集合之前,我們必須先聲明它。有兩種方法可以申明一個(gè)集合類型:
- 通過(guò)TYPE語(yǔ)句在一個(gè)PL/SQL程序中聲明集合類型。
- 通過(guò)CREATE TYPE語(yǔ)句在數(shù)據(jù)中定義一個(gè)嵌套表或者VARRAY類型,這個(gè)類型就是一個(gè)模式級(jí)別的對(duì)象。這種類型就可以用作數(shù)據(jù)庫(kù)表的列的數(shù)據(jù)類型,可以用作對(duì)象類型的屬性,也可以用于聲明PL/SQL變量。
?
2.1聲明關(guān)聯(lián)數(shù)組
關(guān)聯(lián)數(shù)組的TYPE語(yǔ)句的語(yǔ)法如下:
TYPE table_type_name IS TABLE OF datatype [ NOT NULL] INDEX BY index_type;
其中:
??? table_type_name是你所創(chuàng)建的集合類型的名字,datatype是集合中唯一一列的數(shù)據(jù)類型,index_type是用來(lái)組織集合內(nèi)容的索引的數(shù)據(jù)類型。而集合唯一以列的數(shù)據(jù)類型可以是下面這些:
- 標(biāo)量數(shù)據(jù)類型:任何被PL/SQL支持的標(biāo)量數(shù)據(jù)類型,比如VARCHAR2,CLOB,POSITIVE,DATE,或者BOOLEAN。
- 錨定數(shù)據(jù)類型:這種數(shù)據(jù)類型是從一個(gè)數(shù)據(jù)庫(kù)表的列,之前已經(jīng)定義的變量或者帶有%TYPE屬性的游標(biāo)表達(dá)式推導(dǎo)出來(lái)的數(shù)據(jù)類型。我們也可以定義用%ROWTYPE聲明或者根據(jù)一個(gè)用戶定義的記錄類型來(lái)定義一個(gè)記錄的集合。
- 復(fù)雜的數(shù)據(jù)類型:從Oracle 9i數(shù)據(jù)庫(kù)R2版本開始,你也可以把對(duì)象類型和集合類型作為集合的數(shù)據(jù)類型。
集合語(yǔ)法中的index_type定義索引下標(biāo)的數(shù)據(jù)類型。在Oracle 9i數(shù)據(jù)庫(kù)版本R2之前,只能是INDEX BY PLS_INTEGER。從Oracle 9i數(shù)據(jù)庫(kù)版本R2開始,INDEX BY的數(shù)據(jù)類型可以是BINARY_INTEGER、及它的子類型、VARCHAR2(N)或者VARCHAR2列或變量的%TYPE錨定類型。
?
2.2聲明嵌套表
可以數(shù)據(jù)庫(kù)內(nèi)或者PL/SQL代碼塊中聲明嵌套表類型。
在數(shù)據(jù)庫(kù)內(nèi)創(chuàng)建一個(gè)嵌套表類型:
CREATE [OR REPLACE] TYPE type_name AS | IS TABLE OF element_datatype [ NOT NULL ];
刪除數(shù)據(jù)庫(kù)內(nèi)的嵌套表類型:
DROP TYPE type_name [FORCE];
?
在PL/SQL中聲明一個(gè)嵌套表類型:
TYPE type_name IS? TABLE OF element_datatype [ NOT NULL ];
其中:
- ?OR REPLACE:允許我們重創(chuàng)建一個(gè)已經(jīng)存在的類型。通過(guò)在語(yǔ)法中加上REPLACE的方式來(lái)重建類型,而不是先刪除后再重新創(chuàng)建,可以把所有已經(jīng)授予的權(quán)限都完整的保留下來(lái)。
- type_name:一個(gè)合法的SQL或者PL/SQL標(biāo)志符。這也是我們以后在聲明變量或者列時(shí)會(huì)用到的標(biāo)識(shí)符。
- element_datatype:這是集合元素的數(shù)據(jù)類型。集合內(nèi)所有元素都是一種類型的,可以是大部分標(biāo)量數(shù)據(jù)類型、對(duì)象類型、或者REF對(duì)象類型。如果集合的元素是對(duì)象,對(duì)象類型本身不能再帶有一個(gè)集合屬性。如果你創(chuàng)建了一個(gè)其元素是RECORD類型的集合,記錄的字段只能是標(biāo)量或者是獨(dú)享。明確的不可用于集合的數(shù)據(jù)類型包括BOOLEAN、NCHAR、NCLOB、NVARCHAR2、REF CURSOR、TABLE和VARRAY(非SQL數(shù)據(jù)類型)。
- NOT NULL:表明這種類型的變量不能有任何空元素。不過(guò),集合本身可可以是原子級(jí)的空(未初始化)。
- FORCE:這個(gè)關(guān)鍵字告訴數(shù)據(jù)庫(kù)的是,當(dāng)要?jiǎng)h除這個(gè)類型時(shí),就算是其他類型中還有對(duì)這個(gè)類型的引用,也要強(qiáng)行刪除這個(gè)類型。比如,如果在一個(gè)對(duì)象類型的定義中用到了某個(gè)特殊的集合類型,你可以使用FORCE關(guān)鍵字來(lái)強(qiáng)行刪除這個(gè)集合類型。
?
2.3聲明VARRAY
和嵌套表類型的聲明一樣,可以數(shù)據(jù)庫(kù)內(nèi)或者PL/SQL代碼塊中聲明VARRAY類型。
在數(shù)據(jù)庫(kù)內(nèi)創(chuàng)建一個(gè)VARRAY類型:
CREATE [OR REPLACE] TYPE type_name AS | IS?VARRAY?(max_elements)?OF element_datatype [ NOT NULL ];
刪除數(shù)據(jù)庫(kù)內(nèi)的VARRAY類型:
DROP TYPE type_name [FORCE];
在PL/SQL中聲明一個(gè)VARRAY類型:
TYPE type_name IS??VARRAY?(max_elements)?OF element_datatype [ NOT NULL ];
其中:
- OR REPLACE:允許我們重創(chuàng)建一個(gè)已經(jīng)存在的類型。通過(guò)在語(yǔ)法中加上REPLACE的方式來(lái)重建類型,而不是先刪除后再重新創(chuàng)建,可以把所有已經(jīng)授予的權(quán)限都完整的保留下來(lái)。
- type_name:一個(gè)合法的SQL或者PL/SQL標(biāo)志符。這也是我們以后在聲明變量或者列時(shí)會(huì)用到的標(biāo)識(shí)符。
- element_datatype:這是集合元素的數(shù)據(jù)類型。集合內(nèi)所有元素都是一種類型的,可以是大部分標(biāo)量數(shù)據(jù)類型、對(duì)象類型、或者REF對(duì)象類型。如果集合的元素是對(duì)象,對(duì)象類型本身不能再帶有一個(gè)集合屬性。如果你創(chuàng)建了一個(gè)其元素是RECORD類型的集合,記錄的字段只能是標(biāo)量或者是獨(dú)享。明確的不可用于集合的數(shù)據(jù)類型包括BOOLEAN、NCHAR、NCLOB、NVARCHAR2、REF CURSOR、TABLE和VARRAY(非SQL數(shù)據(jù)類型)。
- NOT NULL:表明這種類型的變量不能有任何空元素。不過(guò),集合本身可可以是原子級(jí)的空(未初始化)。
- max_elements:VARRAY中元素的最大數(shù)量,這個(gè)值一旦聲明就不能更改。
- FORCE:這個(gè)關(guān)鍵字告訴數(shù)據(jù)庫(kù)的是,當(dāng)要?jiǎng)h除這個(gè)類型時(shí),就算是其他類型中還有對(duì)這個(gè)類型的引用,也要強(qiáng)行刪除這個(gè)類型。比如,如果在一個(gè)對(duì)象類型的定義中用到了某個(gè)特殊的集合類型,你可以使用FORCE關(guān)鍵字來(lái)強(qiáng)行刪除這個(gè)集合類型。
?
3.集合變量的聲明和初始化
3.1集合變量的聲明
一旦我們創(chuàng)建好了集合類型,我們就可以根據(jù)這個(gè)集合類型聲明該類型的變量。一個(gè)集合變量聲明格式如下:
collection_name collection_type [:=collection_type(...)];
其中,collection_name是集合變量的名字,collection_type具有兩層含義,它即代表著一個(gè)先前已經(jīng)聲明的集合類型的名字,同時(shí)也代表著(如果是嵌套表或者VARRAY的話)和該類型同名的構(gòu)造函數(shù)。
構(gòu)造函數(shù)的名字和類型的名字是相同的,并且接收一個(gè)用逗號(hào)分隔的元素列表作為參數(shù)。如果我們聲明的是一個(gè)嵌套表或者VARRAY變量,我們?cè)谑褂弥氨仨氁葘?duì)這個(gè)變量進(jìn)行初始化。
?
3.2集合變量的初始化
對(duì)于嵌套表類型集合變量和VARRAY類型集合變量,在使用集合變量之前必須要進(jìn)行初始化,而對(duì)于關(guān)聯(lián)數(shù)組類型不需要初始化。下面主要討論嵌套表和VARRY的初始化。
3.2.1通過(guò)構(gòu)造函數(shù)的顯示初始化
通過(guò)構(gòu)造函數(shù)顯示地給集合變量初始。例如:
declare
vnt_employee nt_employee :=nt_employee(); --不帶參數(shù)的構(gòu)造函數(shù)初始化
vnt_employee nt_employee :=nt_employee('張三','李四','王五'); --帶參數(shù)的構(gòu)造函數(shù)初始化
begin
?? null;
end;
?
3.2.2直接賦值時(shí)的隱式初始化
如果兩個(gè)集合實(shí)例是基于同一集合類型,我們可以把其中一個(gè)實(shí)例的全部?jī)?nèi)容拷貝給另一個(gè),這就相當(dāng)于進(jìn)行了初始化。例如:
declare
vnt_employee nt_employee :=nt_employee('James','Lucy','Jordan');
vnt_foregin_employee nt_employee;
begin
???? vnt_foregin_employee := vnt_employee;
end;
?
3.2.3通過(guò)FETCH操作的隱式初始化
在使用FETCH或者 SELECT INTO語(yǔ)句從數(shù)據(jù)庫(kù)提取提取一個(gè)集合并保存到一個(gè)集合變量時(shí),集合變量會(huì)自動(dòng)初始化,就像直接賦值一樣。
declare
vnt_colors nt_color;
begin
select colors into vnt_colors from color_models;? --表color_models的color列是嵌套表類型。
end;
?
3.2.4通過(guò)BULK COLLECT語(yǔ)句的隱式初始
使用BULK COLLECT INTO語(yǔ)句批量提取數(shù)據(jù)并保存到一個(gè)集合變量,集合變量會(huì)自動(dòng)初始化,就像直接賦值一樣。
declare
vnt_employee nt_employee; --未初始化
begin
?? select?e.ename bulk collect intovnt_employee??from emp e;
end;
?
declare
cursor? cur_employee is select e.ename from emp e;
vnt_employee? nt_employee; --未初始化
begin
?? open cur_employee;
?? fetch cur_employee bulk collect into vnt_employee;
?? close cur_employee;
end;
?
4.集合方法
Oracle提供了提供許多內(nèi)置的函數(shù)和過(guò)程可以用于獲取集合的信息或者修改集合的內(nèi)容,這些方法也叫做集合方法。下面給出這些方法的完整列表:
| 方法(函數(shù)或者過(guò)程) | ?? 說(shuō)? 明 |
| COUNT函數(shù) | 返回集合中現(xiàn)有元素的數(shù)量 |
| DELETE過(guò)程 | 從集合中移除一個(gè)或者多個(gè)元素。如果不是重復(fù)移除,會(huì)減少COUNT的值,對(duì)于VARRAY,你只能刪除集合的所有元素 |
| EXISTS函數(shù) | 根據(jù)某個(gè)指定的元素是否已經(jīng)在集合中,返回TURE或者FALES |
| EXTEND過(guò)程 | 增加嵌套表或者VARRAY中元素的個(gè)數(shù),同時(shí)增加COUNT的值 |
| FIRST、LAST函數(shù) | 返回可用的最小(FIRST)和最大(LAST)集合下標(biāo) |
| LIMIT函數(shù) | 返回VARRAY中允許ude最大元素?cái)?shù)量 |
| PRIOD、NEXT函數(shù) | 返回緊挨著指定的下標(biāo)之前(PRIOD)或者之后(NEXT)的下標(biāo)值。你應(yīng)該總是用PRIOD和NEXT在集合內(nèi)遍歷,尤其在使用稀疏(或者可能是稀疏)集合時(shí)更是如此 |
| TRIM過(guò)程 | 從集合的尾部(定義的最大下標(biāo))移除集合元素 |
?
之所以把這些過(guò)程叫做方法,是因?yàn)槭褂眠@些集合內(nèi)置程序的語(yǔ)法不同于調(diào)用過(guò)程和函數(shù)的正規(guī)語(yǔ)法。
?
5.集合類型對(duì)比
| ??? 屬?????性???? | 關(guān)? 聯(lián)? 數(shù)? 組 | 嵌? 套? 表 | ?可變長(zhǎng)數(shù)組 |
| 維度 | 一維 | 一維 | 一維 |
| 是否可用于SQL | 不可用 | 可用 | 可用 |
| 是否可作為表中列的數(shù)據(jù)類型 | 不可用 | 可以;數(shù)據(jù)是在“行外”保存的(一個(gè)獨(dú)立的表) | 可以;數(shù)據(jù)保存在“行內(nèi)”(在同一個(gè)表中) |
| 未初始化時(shí)的狀態(tài) | 空(不能是NULL);元素是為定義 | 自動(dòng)就是NULL的;對(duì)元素的引用是非法的 | 自動(dòng)就是NULL;對(duì)元素的引用是非法的 |
| 初始化 | 在聲明時(shí)自動(dòng)完成 | 通過(guò)構(gòu)造函數(shù),或者賦值,或者fetch操作完成 | 通過(guò)構(gòu)造函數(shù),或者賦值,或者fetch操作完成 |
| 在PL/SQL中元素的引用方式 | BINARY_INTEGER以及其子類型 | VARCHAR2(Oracle 9i數(shù)據(jù)庫(kù)R2版本或者更高版本) | 1到2 147 483 647間的整數(shù) |
| 是否稀疏 | 是 | 開始不是;經(jīng)過(guò)刪除后就成稀疏了 | 不是 |
| 是否有界 | 無(wú)界 | 可以擴(kuò)展 | 有界 |
| 可以隨時(shí)對(duì)任意一個(gè)元素賦值 | 可以 | 不可以,可以需要用EXTEND進(jìn)行擴(kuò)展 | 不可以;可以用EXTEND進(jìn)行擴(kuò)展,而且擴(kuò)展時(shí)不能超出上邊界 |
| 擴(kuò)展的方法 | 給一個(gè)新下標(biāo)指向的元素賦值 | 使用內(nèi)置的EXTEND過(guò)程(或者TRIM進(jìn)行壓縮),沒有預(yù)定義的最大值 | 使用內(nèi)置EXTEND過(guò)程(或者TRIM進(jìn)行壓縮),但是最大只能到聲明的最大尺寸 |
| 可以比較相等與否 | 不可以 | 可以,要求是Oracle 10g或者以后的版本 | 不可以 |
| 是否可以通過(guò)集合操作符進(jìn)行操作 | 不可以 | 可以,要求是Oracle 10g或者以后的版本 | 不可以 |
| 存取數(shù)據(jù)時(shí)是否會(huì)保留順序或者下標(biāo) | N/A | 不保留 | 保留 |
?
6.集合示例
6.1關(guān)聯(lián)數(shù)組示例
declare
? type nt_foregn_employee is table of varchar2(30) index by binary_integer;
? vnt_foregn_employees nt_foregn_employee;
? v_row??????????????? number;
begin
? vnt_foregn_employees(-230002) := 'SCOTT';
? vnt_foregn_employees(-23) := 'JONES';
? vnt_foregn_employees(1) := 'ALLEN';
? vnt_foregn_employees(5934) := 'CLARK';
? vnt_foregn_employees(13342) := 'ADAMS';
? vnt_foregn_employees(8234223) := 'KING';
? --使用FIRST方法獲取集合中的一個(gè)行號(hào)
? v_row := vnt_foregn_employees.first;
? while (v_row is not null) loop
??? dbms_output.put_line(vnt_foregn_employees(v_row));
??? v_row := vnt_foregn_employees.next(v_row);
? end loop;
end;
?
在稀疏集合中,經(jīng)常需要使用NEXT方法遍歷集合,提取數(shù)據(jù)。
?
6.2嵌套表示例
declare
? type nt_employee is table of emp%rowtype;
? vnt_employees nt_employee := nt_employee(); --構(gòu)造函數(shù)顯示初始化
? c_big_number? number := power(2, 31);
? l_start_time? pls_integer;
? cursor cur_employee is
??? select * from emp;
? vrt_employees cur_employee%rowtype;
begin
? open cur_employee;
? loop
??? fetch cur_employee
????? into vrt_employees;
??? exit when cur_employee%notfound;
??? vnt_employees.extend;
??? vnt_employees(vnt_employees.last) := vrt_employees;
? end loop;
? close cur_employee;
?
? dbms_output.put_line(vnt_employees.count);
end;
?
6.3VARRAY實(shí)例
create or? replace type nt_course is varray(5) of varchar2(100);
create table students( student_name varchar2(20) , cource nt_course);
declare
? vnt_nt_courses nt_course := nt_course();
begin
? vnt_nt_courses.extend(2);
? vnt_nt_courses(1) := 'English';
? vnt_nt_courses(2) := 'Chinese';
? insert into students
??? (student_name, cource)
? values
??? ('chiclewu', vnt_nt_courses);
?????
end;
可以使用TABLE函數(shù)把一個(gè)集合映射成數(shù)據(jù)庫(kù)表.例如,要獲取student表中課程列的記錄。
select * from table (select s.cource from students s);
?
參考:
Oracle PL/SQL程序設(shè)計(jì)(第五版) Steven Feuersterin & Bill Pribyl著 張曉明譯
?
?
總結(jié)
以上是生活随笔為你收集整理的Oracle集合类型的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: g723源码详细分析-18-丢包补偿
- 下一篇: 自然语言处理从零到入门 NLP