oracle pl/sql與lightdb plorasql面向對象支持

雖說現在新系統pl/sql已經很少用了,但是在信創遷移過程中,仍然有很多oracle pl/sql過程、函數、包需要能夠無縫的移植到信創數據庫,比如在很多風控系統移植lightdb的過程中,就遇到了很多,甚至還有pro*c。所以纔有了本文。

-- 最常用,用於集合處理

DECLARE
CURSOR allrows_cur IS SELECT * FROM emp; TYPE employee_aat IS TABLE OF emp%ROWTYPE INDEX BY PLS_INTEGER; -- 帶index by,關聯數組,Associative array l_employees employee_aat; TYPE employee_aat2 IS TABLE OF emp%ROWTYPE; -- 不帶index by,嵌套表 l_employees2 employee_aat2; BEGIN OPEN allrows_cur; LOOP FETCH allrows_cur BULK COLLECT INTO l_employees LIMIT 100; /* Process the data by scanning through the collection. */ FOR l_row IN 1 .. l_employees.COUNT LOOP dbms_output.put_line (l_employees(l_row).ename || '-' || l_employees(l_row).EMPNO); END LOOP; EXIT WHEN allrows_cur%NOTFOUND; END LOOP; CLOSE allrows_cur; SELECT * BULK COLLECT INTO l_employees2 FROM emp; FOR l_row IN 1 .. l_employees2.COUNT LOOP dbms_output.put_line ('l_employees2==' || l_employees2(l_row).ename || '-' || l_employees2(l_row).EMPNO); END LOOP; END;

SMITH-7369
ALLEN-7499
WARD-7521
JONES-7566
MARTIN-7654
BLAKE-7698
CLARK-7782
SCOTT-7788
KING-7839
TURNER-7844
ADAMS-7876
JAMES-7900
FORD-7902
MILLER-7934
l_employees2==SMITH-7369
l_employees2==ALLEN-7499
l_employees2==WARD-7521
l_employees2==JONES-7566
l_employees2==MARTIN-7654
l_employees2==BLAKE-7698
l_employees2==CLARK-7782
l_employees2==SCOTT-7788
l_employees2==KING-7839
l_employees2==TURNER-7844
l_employees2==ADAMS-7876
l_employees2==JAMES-7900
l_employees2==FORD-7902
l_employees2==MILLER-7934

注:我不喜歡使用可變長度數組,所以本文不包含它。

Table 5-1 PL/SQL Collection Types

Collection TypeNumber of ElementsIndex TypeDense or SparseUninitialized StatusWhere DefinedCan Be ADT Attribute Data Type

Associative array (or index-by table)

Unspecified

String or PLS_INTEGER

Either

Empty

In PL/SQL block or package

No

VARRAY (variable-size array)

Specified

Integer

Always dense

Null

In PL/SQL block or package or at schema level

Only if defined at schema level

Nested table

Unspecified

Integer

Starts dense, can become sparse

Null

In PL/SQL block or package or at schema level

Only if defined at schema level

Number of Elements

If the number of elements is specified, it is the maximum number of elements in the collection. If the number of elements is unspecified, the maximum number of elements in the collection is the upper limit of the index type.

Dense or Sparse

dense collection has no gaps between elements—every element between the first and last element is defined and has a value (the value can be NULL unless the element has a NOT NULL constraint). A sparse collection has gaps between elements.

Uninitialized Status

An empty collection exists but has no elements. To add elements to an empty collection, invoke the EXTEND method (described in "EXTEND Collection Method").

null collection (also called an atomically null collection) does not exist. To change a null collection to an existing collection, you must initialize it, either by making it empty or by assigning a non-NULL value to it (for details, see "Collection Constructors" and "Assigning Values to Collection Variables"). You cannot use the EXTEND method to initialize a null collection.

自定義記錄類型

CREATE TABLE Book_table (
Booknum NUMBER,
Section VARCHAR2(20),
Title VARCHAR2(20),
Author VARCHAR2(20),
Available CHAR(1)
);
INSERT INTO Book_table (
Booknum, Section, Title, Author, Available
)
VALUES (
121001, 'Classic', 'Iliad', 'Homer', 'Y'
);
INSERT INTO Book_table (
Booknum, Section, Title, Author, Available
)
VALUES (
121002, 'Novel', 'Gone with the Wind', 'Mitchell M', 'N'
);
SELECT * FROM Book_table ORDER BY Booknum;
DECLARE
TYPE Book_list_record IS RECORD (
Booknum NUMBER,
Section VARCHAR2(20),
Title VARCHAR2(20),
Author VARCHAR2(20),
Available CHAR(1)
);
TYPE Book_list_t1 IS TABLE OF Book_list_record;
v_Book_list Book_list_t1;  -- 嵌套表
BEGIN
SELECT Booknum, Section, Title, Author, Available BULK COLLECT INTO v_Book_list FROM Book_table;
FOR l_row IN 1 .. v_Book_list.COUNT
LOOP
  dbms_output.put_line ('v_Book_list==' || v_Book_list(l_row).Booknum || '-' || v_Book_list(l_row).Title);
END LOOP;
END;

v_Book_list==121001-Iliad
v_Book_list==121002-Gone with the Wind

  記錄類型和對象類型的差異,需要特別注意,對象需要通過構造器設置值,記錄類型和ROWTYPE類型可以賦值。直接將SELECT Booknum, Section, Title, Author, Available BULK COLLECT INTO v_Book_list賦值給對象嵌套表,將報值不足。

預定義基於對象的嵌套表類型

CREATE OR REPLACE TYPE Book_t1 AS OBJECT (
Booknum NUMBER,
Section VARCHAR2(20),
Title VARCHAR2(20),
Author VARCHAR2(20),
Available CHAR(1)
);

CREATE OR REPLACE TYPE Book_list_t AS TABLE OF Book_t1;

DECLARE
v_Book_list Book_list_t;  -- 嵌套表
BEGIN
SELECT Book_t1(Booknum, Section, Title, Author, Available)/* 對象類型特殊的地方 */ BULK COLLECT INTO v_Book_list FROM Book_table;
FOR l_row IN 1 .. v_Book_list.COUNT
LOOP
  dbms_output.put_line ('v_Book_list==' || v_Book_list(l_row).Booknum || '-' || v_Book_list(l_row).Title);
END LOOP;
END;

v_Book_list==121001-Iliad
v_Book_list==121002-Gone with the Wind

is table of 和 as table of

在創建類型的時候是一樣的,都可以生效。

CREATE OR REPLACE TYPE Book_list_t IS TABLE OF Book_t1;

CREATE OR REPLACE TYPE Book_list_t AS TABLE OF Book_t1;

都能生效。

但是在過程內定義嵌套表的時候,只能用IS TABLE OF,不能用AS TABLE OF,會報錯。

DECLARE
TYPE employee_aat2 AS TABLE OF emp%ROWTYPE;   -- 不帶index by,嵌套表
l_employees2 employee_aat2;

BEGIN

SELECT * BULK COLLECT INTO l_employees2 FROM emp;
FOR l_row IN 1 .. l_employees2.COUNT
LOOP
  dbms_output.put_line ('l_employees2==' || l_employees2(l_row).ename || '-' || l_employees2(l_row).EMPNO);
END LOOP;
END;

SQL 錯誤 [6550] [65000]: ORA-06550: 第 2 行, 第 23 列: 
PLS-00103: 出現符號 "TABLE"在需要下列之一時:
 object
   opaque

對象嵌套表的構造與使用

CREATE TYPE address_typ AS OBJECT (
 street VARCHAR2(30),
 city VARCHAR2(20),
 state CHAR(2),
 postal_code VARCHAR2(6) );

CREATE OR REPLACE TYPE employee_typ AS OBJECT (
 employee_id NUMBER(6),
 first_name VARCHAR2(20),
 last_name VARCHAR2(25),
 email VARCHAR2(25),
 phone_number VARCHAR2(20),
 hire_date DATE,
 job_id VARCHAR2(10),
 salary NUMBER(8,2),
 commission_pct NUMBER(2,2),
 manager_id NUMBER(6),
 department_id NUMBER(4),
 address address_typ,
 MAP MEMBER FUNCTION get_idno RETURN NUMBER,
 MEMBER PROCEDURE display_address ( SELF IN OUT NOCOPY employee_typ ) );
 

CREATE OR REPLACE TYPE BODY employee_typ AS
 MAP MEMBER FUNCTION get_idno RETURN NUMBER IS
 BEGIN
 RETURN employee_id;
 END;
 MEMBER PROCEDURE display_address ( SELF IN OUT NOCOPY employee_typ ) IS
 BEGIN
 DBMS_OUTPUT.PUT_LINE(first_name || ' ' || last_name);
 DBMS_OUTPUT.PUT_LINE(address.street);
 DBMS_OUTPUT.PUT_LINE(address.city || ', ' || address.state || ' ' ||
 address.postal_code);
 END;
END;


DECLARE
 TYPE emps IS TABLE OF employee_typ;
 emp_list emps := emps(); -- emp is atomically null
BEGIN
 emp_list.extend(3);
-- call the constructor for employee_typ
 emp_list(1) := employee_typ(315, 'Francis', 'Logan', 'FLOGAN',
 '415.555.0100', sysdate,'SA_MAN', 11000, 0.15, 101, 110,
 address_typ('376 Mission', 'San Francisco', 'CA', '94222'));
 
 emp_list(2) := employee_typ(215, '2Franis', '2Loan', '2FLGAN',
 '245.555.0100', sysdate,'SA_MAN', 11000, 0.15, 101, 110,
 address_typ('237 Mission', '2Sn Francisco', '2C', '94222'));
 
 FOR i IN 1..emp_list.count loop
   DBMS_OUTPUT.PUT_LINE(emp_list(i).first_name || ' from dbms_output ' || emp_list(i).last_name); -- display details
   emp_list(i).display_address(); -- call object method to display details
 END LOOP;
END;
-- 輸出
Francis from dbms_output Logan
Francis Logan
376 Mission
San Francisco, CA 94222
2Franis from dbms_output 2Loan
2Franis 2Loan
237 Mission
2Sn Francisco, 2C 94222
 from dbms_output 

對象類型不僅可以包含成員,也可以包含成員函數、構造器(只能通過java或c編寫,不支持PL/SQL定義)、靜態成員函數等,典型的面向對象。

集合類型上的默認支持函數。

表函數支持

嵌套表和關聯數組都支持作爲表函數的參數。

CREATE OR REPLACE PACKAGE pkg AS
TYPE rec IS RECORD(f1 NUMBER, f2 VARCHAR2(30));
-- TYPE mytab IS TABLE OF rec INDEX BY pls_integer; -- 默認空集合
TYPE mytab IS TABLE OF rec;  -- 默認未初始化,需要顯示初始化
END;

DECLARE
v1 pkg.mytab; -- collection of records
v2 pkg.rec;
c1 SYS_REFCURSOR;
BEGIN
    v1 := pkg.mytab();  -- 嵌套表需要
    v1.extend(2);     -- 嵌套表需要
v1(1).f1 := 1;
v1(1).f2 := 'one';
OPEN c1 FOR SELECT * FROM TABLE(v1);
FETCH c1 INTO v2;
CLOSE c1;
DBMS_OUTPUT.PUT_LINE('Values in record are ' || v2.f1 || ' and ' || v2.f2);
END;

 

自定義對象類型及嵌套表在Oracle及EDB中的實現

  在edb中,基於對象的自定義類型是通過模擬schema來實現的,和package一樣,即type_name就是schema_name,成員函數這些存儲在其對應的schema下,這樣也不會污染全局pg_proc。而自定義類型又可以作爲package的成員之一,這就會比較複雜。package.type.method或pakcage.type.member和pakage.table.attribute看起來衝突,就有個serach_path優先級的問題。在PG默認中,一般先搜索current_schema、其次public、然後纔是其他schema,當然也可以配置,但一般不會修改。

SELECT * FROM user_types;

BOOK_LIST_T R¡P<1àcÇ ï COLLECTION
BOOK_T1 R¡@<1àcÇ ï OBJECT
EMPLOYEE_TYP R¡u<1àcÇ ï OBJECT
ADDRESS_TYP R¡Z<1àcÇ ï OBJECT


SELECT * FROM USER_TYPE_ATTRS;  -- 存儲屬性
SELECT * FROM USER_TYPE_METHODS;  -- 存儲成員函數

SELECT * FROM DBA_PROCEDURES WHERE object_name='PKG';  -- 尚未找到類型存儲的位置

OWNER |OBJECT_NAME|PROCEDURE_NAME|OBJECT_ID|SUBPROGRAM_ID
-----------+-----------+--------------+---------+-------------
SYSTEM |PKG | | 183968| 0
  這意味着,如果有相同的表名和類型名,就不知道找誰。所以,一種實現就是不允許類型名和表名相同以保證唯一性。

  在oracle中是4級存儲,schema.package.type.member。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章