1. Oracle翻译注意事项
说明:我们将采取对比原有sql的语句来介绍和解释Oracle语句和编码要求
1.1. Oracle常用函数
4.1.1 INSTR 函数的使用
概述:oracle的INSTR 函数相当于sql中的CHARINDEX函数
Sql用法格式:CHARINDEX (目标字符串 , 源字符串 [ , 起始位置 ])
例子1:SELECT CHARINDEX('C','ABCDE')
输出结果为:3
说明:在“源字符串”中查找“目标字符串”的位置。
例子2:SELECT CHARINDEX('C','ABCDEFXYZCQA',4)
输出结果为:10
说明:从“源字符串”的第4个字符(包含第4个字符)中查找“目标字符串”的位置。
Oracle用法格式:INSTR(源字符串, 目标字符串[,起始位置] [,匹配序号])
例子1:SELECT INSTR('CORPORATE FLOOR','OR', 3, 2) FROM DUAL;
输出结果:14
说明:目标字符串为'OR',起始位置为3,取第2个匹配项的位置。
默认查找顺序为从左到右。
例子2:SELECT INSTR('CSORPORATE FLOOR','OR', 3, 2) FROM DUAL;
输出结果:6
例子3:SELECT INSTR('CORPORATE FLOOR', 'OR', -1, 2) FROM DUAL;
输出结果:5
说明:当起始位置为负数的时候,从右边开始查找。
例子4:SELECT INSTR('CORPORATE FLOOR','OR') FROM DUAL;
输出结果:2
说明:此时默认起始位置1,匹配序号为1
4.1.2 SUBSTR 函数的使用
概述:oracle的SUBSTR函数相当于sql中的 SUBSTRING函数
Sql用法格式:SUBSTRING ( expression , start , length )
例子1:SELECT SUBSTRING('ABCDEFXYZCQA',4,3)
输出结果:DEF
说明:SELECT SUBSTRING('ABCDEFXYZCQA',4) 将报错:substring 函数要求有 3 个参数。
Oracle用法格式: substr( string, start_position [, length ] )
例子1:SELECT SUBSTR('THISISATEST', 6, 2) FROM DUAL;
输出结果:SA
说明:从第6个字符(包含第6个字符)开始取2位
例子 2:SELECT SUBSTR('THISISATEST', 6) FROM DUAL;
输出结果:SATEST
说明:从第6个字符(包含第6个字符)开始取到结束
例子3:SELECT SUBSTR('TECHONTHENET', -8, 5) FROM DUAL;
输出结果:ONTHE
说明:当起始位置为负数的时候,从右边开始查找。然后再从左往右取5位
4.1.3 NVL 函数的使用
概述:oracle的NVL函数相当于sql中的 ISNULL函数
Sql用法格式:ISNULL ( check_expression , replacement_value )
说明:在 check_expression 为 NULL时将返回replacement_value,否则返回check_expression 的值,replacement_value 必须与 check_expresssion 具有相同的类型。
Oracle用法格式:NVL ( check_expression , replacement_value )
说明:用法同上
4.1.4 CAST 函数的使用
概述:oracle的CAST函数与sql中的相同,将某种数据类型的表达式显式转换为另一种数据类型。
说明:对于将某种数据类型的表达式显式转换为另一种数据类型,sql中提供了cast
和convert两种函数,但是oracle中没有convert函数而是提供其他的函数,
具体创建如下的TO_DATE、TO_CHAR、TO_NUMBER
4.1.5 TO_DATE 函数的使用
概述:是把字符串转换为数据库中的日期类型
例子:
当我们在翻译的时候定义变量V_FIELDVALUE 是一个 VARCAR2(20)的数据类型时,但是该变量需要作为一个过滤条件的值时如:
OPEN RCT1 FOR SELECT * FROM AIR_CC_HEADER A WHERE A.FLIGHT_TIME >= V_FLIGHTFROM;
这时必须把V_FLIGHTFROM变换为 Date类型:
V_FLIGHTFROM := TO_DATE(V_FIELDVALUE,'YYYY-MM-DD ,HH24:MI:SS')
4.1.6 TO_CHAR和 TO_NCHAR函数的使用
概述:是把日期或数字转换为字符串
例子1:
同样我们定义了变量V_FIELDVALUE的数据类型为VARCAR2(20),此时我想对该日期加上一天,再拼凑到动态的oracle语句中,我们该这么做:
OPEN RCT1 FOR 'SELECT * FROM AIR_CC_HEADER WHERE EXPIRE_DATE
<= TO_DATE(''' || TO_CHAR((TO_DATE(V_FIELDVALUE, 'YYYY-MM-DD HH24:MI:SS') + 1),'YYYY-MM-DD HH24:MI:SS') || ''',''YYYY-MM-DD HH24:MI:SS'')';
或者
OPEN RCT1 FOR 'SELECT * FROM AIR_CC_HEADER WHERE EXPIRE_DATE
<= TO_DATE(''' || V_FIELDVALUE || ''',''YYYY-MM-DD HH24:MI:SS'') + 1';
说明:Oracle中没有像sql中有CONVERT函数,所以在翻译过程中如果有遇到类似这样的sql语句:
CONVERT(VARCHAR(20), CTN_MADE_DATE, 120)
使用TO_DATE函数将其转换为如下写法:
TO_CHAR (CTN_MADE_DATE , 'YYYY-MM-DD HH24:MI:SS')
4.1.7 TO_NUMBER函数的使用
概述:是将字符转换为数字
4.1.8 LENGTH 函数的使用
概述:Oracle的LENGTH函数相当于Sql的LEN函数,用于计算字符串长度。
4.1.9 RTRIM和LTRIM 函数
概述:Oracle的RTRIM和LTRIM函数与Sql相同,RTRIM 删除字符变量中的尾随空格;LTRIM 字符删除字符变量中的起始空格。
4.1.10 REPLACE 函数的使用
概述:REPLACE('STRING','S1','S2'),STRING希望被替换的字符或变量,
S1被替换的字符串,S2要替换的字符串。
例子:SELECT REPLACE('ABC,DEF,GHI',',',':') FROM DUAL
输出结果:ABC:DEF:GHI
4.1.11 SYSDATE 函数的使用
概述:oracle的SYSDATE类似与sql的GETDATE()函数的功能,用户获取当前时间。
Sql用法格式:
例子1:SELECT GETDATE()
输出结果:2008-07-10 01:28:10.637
Oracle用法格式:
例子1:SELECT SYSDATE FROM DUAL
输出结果:2008-7-10 1:28:42
4.1.12 ADD_MONTHS()函数的使用
概述:ADD_MONTHS(X,Y)函数用于计算X加上Y个月的结果。如果Y是负数,就从X中减去Y个月。
例子1:SELECT ADD_MONTHS(TO_DATE('2007-7-7','YYYY-MM-DD'),2) FROM DUAL
输出结果:2007-9-7
例子2:SELECT ADD_MONTHS(TO_DATE('2007-7-7','YYYY-MM-DD'),-2) FROM DUAL
输出结果:2007-5-7
4.1.13 LAST_DAY()函数的使用
概述:LAST_DAY(X)函数用于计算包含X的月的最后一天。
例子1:SELECT LAST_DAY(TO_DATE('2007-7-7','YYYY-MM-DD')) FROM DUAL;
输出结果:2007-7-31
4.1.14 NEXT_DAY()函数的使用
概述:NEXT_DAY(X,DAY)函数用于计算从X开始,下一个DAY的日期;参数DAY是一个文本字符串,
例如:星期一
例子1:SELECT NEXT_DAY(TO_DATE('2008-7-19','YYYY-MM-DD'),'星期一') FROM DUAL;
输出结果:2008-7-21
4.1.15 ROUND()函数的使用
概述:ROUND(X[,UNIT])函数用于对X进行取整。默认情况下,X取整为最近的一天。UNIT是一个可选字符串参数,它指明要取整的单元。
例子1:SELECT ROUND(TO_DATE('2007-5-7','YYYY-MM-DD'),'YY') FROM DUAL;
输出结果:2007-1-1
例子2:SELECT ROUND(TO_DATE('2007-8-7','YYYY-MM-DD'),'YY') FROM DUAL;
输出结果:2008-1-1
例子3:SELECT ROUND(TO_DATE('2007-5-7','YYYY-MM-DD'),'MM') FROM DUAL;
输出结果:2007-5-1
例子4:SELECT ROUND(TO_DATE('2007-5-17','YYYY-MM-DD'),'MM') FROM DUAL;
输出结果:2007-6-1
例子5:SELECT ROUND(TO_DATE('2007-5-7 11:10:23','YYYY-MM-DD HH24:MI:SS'),'DD') FROM DUAL;
输出结果:2007-5-7
例子6:SELECT ROUND(TO_DATE('2007-5-7 13:10:23','YYYY-MM-DD HH24:MI:SS'),'DD') FROM DUAL;
输出结果:2007-5-8
例子7:SELECT ROUND(TO_DATE('2007-5-7 13:10:23','YYYY-MM-DD HH24:MI:SS'),'HH24') FROM DUAL;输出结果:2007-5-7 13:00:00
例子8:SELECT ROUND(TO_DATE('2007-5-7 13:45:23','YYYY-MM-DD HH24:MI:SS'),'HH24') FROM DUAL;
输出结果:2007-5-7 14:00:00
4.1.16 TRUNC()函数的使用
概述:TRUNC(X,UNIT)函数用于对X进行截断。默认情况下,X被截断为当天的开始时间。UNIT是一个可选字符串参数,它指明要取整的单元。
例子1:SELECT TRUNC(TO_DATE('2007-5-7','YYYY-MM-DD'),'YY') FROM DUAL;
输出结果:2007-1-1
例子2:SELECT TRUNC(TO_DATE('2007-8-7','YYYY-MM-DD'),'YY') FROM DUAL;
输出结果:2007-1-1
例子3:SELECT TRUNC(TO_DATE('2007-5-7','YYYY-MM-DD'),'MM') FROM DUAL;
输出结果:2007-5-1
例子4:SELECT TRUNC(TO_DATE('2007-5-17','YYYY-MM-DD'),'MM') FROM DUAL;
输出结果:2007-5-1
例子5:SELECT TRUNC(TO_DATE('2007-5-7 11:10:23','YYYY-MM-DD HH24:MI:SS'),'DD') FROM DUAL;
输出结果:2007-5-7
例子6:SELECT TRUNC(TO_DATE('2007-5-7 13:10:23','YYYY-MM-DD HH24:MI:SS'),'DD') FROM DUAL;
输出结果:2007-5-7
例子7:SELECT TRUNC(TO_DATE('2007-5-7 13:10:23','YYYY-MM-DD HH24:MI:SS'),'HH24') FROM DUAL;输出结果:2007-5-7 13:00:00
例子8:SELECT TRUNC(TO_DATE('2007-5-7 13:45:23','YYYY-MM-DD HH24:MI:SS'),'HH24') FROM DUAL;
输出结果:2007-5-7 13:00:00
4.1.17 REPLICATE()函数的使用
Sql用法格式:
概述:REPLICATE([expression],[count])按指定次数重复字符表达式。
例子 :Select Replicate('abc',2)
输出结果:abcabc
例子 :Select Replicate('abc',-2)
输出结果:null
例子 :Select Replicate('abc',0)
输出结果:无
Oracle用法格式:
DECLARE
V_COUNT INTEGER := 3;
V_RESULT VARCHAR(2000);
BEGIN
FOR I IN 1 .. V_COUNT LOOP
V_RESULT := V_RESULT || 'ABC';
END LOOP;
DBMS_OUTPUT.PUT_LINE(V_RESULT);
END;
4.2. Oracle常用运算符
4.2.1 变量赋值
Sql用法: DECLARE @FRTCUSTNAME NVARCHAR(200),
@FRTCUSTTYPE NVARCHAR(20)
SELECT @FRTCUSTNAME = N'ABC',
@FRTCUSTTYPE = N'DEF'
PRINT @FRTCUSTNAME+@FRTCUSTTYPE
打印结果:ABCDEF
Oracle用法 : DECLARE V_FRTCUSTNAME VARCHAR2(200);
V_FRTCUSTTYPE VARCHAR2(20);
BEGIN
V_FRTCUSTNAME := 'ABC'; --变量赋值不是用 “=” 号,而是用 “:=”
V_FRTCUSTTYPE := 'DEF';
DBMS_OUTPUT.PUT_LINE(V_FRTCUSTNAME||V_FRTCUSTTYPE);
END;
或者直接这样赋值:
DECLARE V_FRTCUSTNAME VARCHAR2(200) :='ABC';
V_FRTCUSTTYPE VARCHAR2(20) :='DEF';
BEGIN
DBMS_OUTPUT.PUT_LINE(V_FRTCUSTNAME||V_FRTCUSTTYPE);
END;
打印结果:ABCDEF
说明:对于从数据库取出的数据赋值给某个变量我们一般采取:
SELECT COLNAME INTO V_变量 FROM TABLENAME WHERE CONDITION ;
的方式来赋值。
例子1:SELECT BL_TYPE INTO V_BLTYPE FROM OZ_BK_HEADER WHERE JOB_ORDER_ID = V_JOBORDERID但是这样的赋值方式存在隐患,当WHERE的条件不成立时,查询出空行时,此时的赋值将有异常。
于是我们在翻译的时候为防止异常的发生我们一般采用以下两种赋值方式:
方式1采用隐身游标来赋值(建议使用该方法):
FOR REC IN (SELECT BL_TYPE FROM OZ_BK_HEADER WHERE JOB_ORDER_ID = V_JOBORDERID)
LOOP
V_BL_TYPE := REC.BL_TYPE;
END LOOP;
方式 2 采用捕获异常的方式来赋值:
BEGIN
SELECT BL_TYPE INTO V_BLTYPE FROM OZ_BK_HEADER WHERE JOB_ORDER_ID = V_JOBORDERID;
EXCEPTION WHEN OTHERS THEN
V_BLTYPE := '赋默认值';
END;
但对于聚集函数就可以不用使用上述的方式了。如:
SELECT COUNT(1) INTO V_TOTALRECORDS FROM TMP_OZ_HEADER_SESSION;
可以不使用下列形式,因为聚集函数都能返回一行:
FOR REC IN (SELECT COUNT(1) AS CN INTO V_TOTALRECORDS FROM TMP_OZ_HEADER_SESSION)
LOOP
V_COUNT := REC.CN;
END LOOP;
4.2.2 字符串连接
Sql用法:
SELECT 'ABC' + 'DEF'
输出结果:ABCDEF
Oracle用法:
SELECT 'ABC' || 'DEF' FROM DUAL 或者
SELECT CONCAT('ABC','DEF') FROM DUAL
输出结果:ABCDEF
4.3. Oracle PL/SQL 基础
4.3.1 条件判断语句 IF … THEN… ELSIF … THEN … END IF;
DECLARE
NUM INTEGER := 3;
BEGIN
IF NUM < 0 THEN
DBMS_OUTPUT.PUT_LINE('负数');
ELSE IF NUM > 0 THEN
DBMS_OUTPUT.PUT_LINE('正数');
ELSE
DBMS_OUTPUT.PUT_LINE('0');
END IF;
END IF;
END;
说明:当有多个的 ELSE IF 的时候,为了使代码简洁、美观,易于浏览我们建议将 ELSE IF 替换为:ELSIF。如以上示例可替换如下:
DECLARE
NUM INTEGER := 3;
BEGIN
IF NUM < 0 THEN
DBMS_OUTPUT.PUT_LINE('负数');
ELSIF NUM > 0 THEN
DBMS_OUTPUT.PUT_LINE('正数');
ELSE
DBMS_OUTPUT.PUT_LINE('0');
END IF;
END;
4.3.2 循环语句 LOOP....EXIT....END LOOP;
DECLARE
V_NUM INTEGER := 1;
V_SUM INTEGER := 0;
BEGIN
LOOP
V_SUM := V_SUM + V_NUM;
DBMS_OUTPUT.PUT_LINE(V_NUM);
IF V_NUM = 4 THEN
EXIT;
END IF;
DBMS_OUTPUT.PUT_LINE('+');
V_NUM := V_NUM + 1;
END LOOP;
DBMS_OUTPUT.PUT_LINE('=');
DBMS_OUTPUT.PUT_LINE(V_SUM);
END;
输出结果:1+2+3+4 = 10
4.3.3 循环语句 LOOP....EXIT WHEN ....END LOOP;
DECLARE
V_NUM INTEGER := 1;
V_SUM INTEGER := 0;
BEGIN
LOOP
V_SUM := V_SUM + V_NUM;
DBMS_OUTPUT.PUT_LINE(V_NUM);
EXIT WHEN V_NUM = 4;
DBMS_OUTPUT.PUT_LINE('+');
V_NUM := V_NUM + 1;
END LOOP;
DBMS_OUTPUT.PUT_LINE('=');
DBMS_OUTPUT.PUT_LINE(V_SUM);
END;
输出结果: 1+2+3+4 = 10
4.3.4 循环语句 WHILE...LOOP...END LOOP;
DECLARE
V_NUM INTEGER := 1;
V_SUM INTEGER := 0;
BEGIN
WHILE V_NUM <= 4 LOOP
V_SUM := V_SUM + V_NUM;
DBMS_OUTPUT.PUT_LINE(V_NUM);
IF V_NUM < 4 THEN
DBMS_OUTPUT.PUT_LINE('+');
END IF;
V_NUM := V_NUM + 1;
END LOOP;
DBMS_OUTPUT.PUT_LINE('=');
DBMS_OUTPUT.PUT_LINE(V_SUM);
END;
输出结果:1+2+3+4 = 10
4.3.5 循环语句 FOR...IN..LOOP....END LOOP;
DECLARE
V_NUM INTEGER;
V_SUM INTEGER := 0;
BEGIN
FOR V_NUM IN 1 .. 4 LOOP
V_SUM := V_SUM + V_NUM;
DBMS_OUTPUT.PUT_LINE(V_NUM);
IF V_NUM < 4 THEN
DBMS_OUTPUT.PUT_LINE('+');
END IF;
END LOOP;
DBMS_OUTPUT.PUT_LINE('=');
DBMS_OUTPUT.PUT_LINE(V_SUM);
END;
输出结果:1+2+3+4 = 10
4.3.6 游标的使用
1.声明由于保存列值的变量
2.声明游标
3.打开游标
4.从游标中读取数记录
5.关闭游标
例子:
方法一(显式游标):
--STEP1 : DECLARE THE VARIABLES
V_PRODUCT_ID VARCHAR2(20);
V_TITLE_NAME VARCHAR2(20);
--STEP 2:DECLARE THE CURSOR
CURSOR CUR_PRODUCT IS
SELECT PRODUCT_ID FROM PRODUCTS ORDER BY PRODUCT_ID;
-- STEP 3:OPEN THE CURSOR
BEGIN
OPEN CUR_PRODUCT;
LOOP
-- STEP 4:FETCH THE ROWS FOM THE CURSOR
FETCH CUR_PRODUCT INTO V_PRODUCT_ID;
EXIT WHEN CUR_PRODUCT%NOTFOUND;
BEGIN
SELECT TITLE_NAME INTO V_TITLE_NAME FROM TITLES WHERE PRODUCT_ID = V_PRODUCT_ID;
END;
END LOOP;
-- STEP 5:CLOSE THE CURSOR
CLOSE CUR_PRODUCT;
END;
方法二(显式游标):
--STEP1 : DECLARE THE VARIABLES
V_PRODUCT_ID VARCHAR2(20);
V_TITLE_NAME VARCHAR2(20);
--STEP 2:DECLARE THE CURSOR
CURSOR CUR_PRODUCT IS
SELECT PRODUCT_ID FROM PRODUCTS ORDER BY PRODUCT_ID;
-- STEP 3:OPEN THE CURSOR
BEGIN
OPEN CUR_PRODUCT;
-- STEP 4:FETCH THE ROWS FOM THE CURSOR
FETCH CUR_PRODUCT INTO V_PRODUCT_ID;
WHILE(CUR_PRODUCT%FOUND) LOOP
BEGIN
SELECT TITLE_NAME INTO V_TITLE_NAME FROM TITLES WHERE PRODUCT_ID = V_PRODUCT_ID;
FETCH CUR_PRODUCT INTO V_PRODUCT_ID;
END;
END LOOP;
-- STEP 5:CLOSE THE CURSOR
CLOSE CUR_PRODUCT;
END;
说明:对比方法一和方法二,体会 “%NOTFOUND” 和 “%FOUND” 的属性的用法。游标的另外两个属性为:%ISOPEM, %ROWCOUNT。这四个属性的意思为:
%ISOPEN判断游标是否被打开,如果打开%ISOPEN等于true,否则等于false;
%FOUND、%NOTFOUND判断游标所在的行是否有效,如果有效,则%FOUNDD等于true,否则等于false;
%ROWCOUNT返回当前位置为止游标读取的记录行数。
方法三(隐式游标):
V_TITLE_NAME VARCHAR2(20);
BEGIN
FOR REC IN ( SELECT PRODUCT_ID FROM PRODUCTS ORDER BY PRODUCT_ID) LOOP
BEGIN
SELECT TITLE_NAME INTO V_TITLE_NAME FROM TITLES WHERE PRODUCT_ID = REC.PRODUCT_ID;
END;
END LOOP;
END;
说明:利用FOR循环的功能,可以增强在游标访问记录的能力。当使用FOR循环时,可以不显式的打开和关闭游标---FOR循环会自动执行这些操作。
4.3.7 序列的使用
1.基本语法
(1) 创建序列命令
CREATE SEQUENCE [USER.]SEQUENCE_NAME
[INCREMENT BY N]
[START WITH N]
[MAXVALUE N | NOMAXVALUE]
[MINVALUE N | NOMINVALUE]
[CYCLE|NOCYCLE]
[CACHE|NOCACHE]
[ORDER|NOORDER];
INCREMENT BY: 指定序列号之间的间隔,该值可为正的或负的整数,但不可为0。序列为升序忽略该子句时,缺省值为1。
START WITH: 指定生成的第一个序列号。在升序时,序列可从比最小值大的值开始,缺省值为序列的最小值。
对于降序,序列可由比最大值小的值开始,缺省值为序列的最大值。
MAXVALUE: 指定序列可生成的最大值。
NOMAXVALUE: 为升序指定最大值为1027,为降序指定最大值为-1。
MINVALUE: 指定序列的最小值。
NOMINVALUE: 为升序指定最小值为1。为降序指定最小值为-1026。
CYCLE: 循环使用,用到最大值再返。
CACHE: 指定CACHE的值。如果指定CACHE值,ORACLE就可以预先在内存里面放置一些SEQUENCE,这样存取的快些。
CACHE里面的取完后,ORACLE自动再取一组到CACHE。 使用CACHE或许会跳号,
比如数据库突然不正常DOWN掉(SHUTDOWN ABORT),CACHE 中的 SEQUENCE 就会丢失。所以可以在 CREATE SEQUENCE 的时候用 NOCACHE 防止这种情况。
ORDER: 顺序使用序列值。
(2) 更改序列
ALTERSEQUENCE [USER.]SEQUENCE_NAME
[INCREMENT BY N]
[MAXVALUE N| NOMAXVALUE ]
[MINVALUE N | NOMINVALUE]
[CYCLE|NOCYCLE]
[CACHE|NOCACHE]
[ORDER|NOORDER];
修改序列可以:
A.修改未来序列值的增量。
B.设置或撤消最小值或最大值。
C.转变缓冲序列的数目。
D.指定序列号是否是有序。
(3) 删除序列
DROP SEQUENCE [USER.]SEQUENCE_NAME;
2. 序列的使用
序列提供两个方法,NEXTVAL 和 CURRVAL。
NEXTVAL:取序列的下一个值,一次 NEXTVAL 会增加一次 SEQUENCE 的值。
CURRVAL:取序列的当前值。
但是要注意的是:第一次 NEXTVAL 返回的是初始值;随后的 NEXTVAL 会自动增加你定义的 INCREMENT BY 值,然后返回增加后的值。CURRVAL 总是返回当前 SEQUENCE 的值,但是在第一次 NEXTVAL 初始化之后才能使用 CURRVAL,否则会出错。
4.4. 存储过程翻译注意事项
4.4.1 原Sql的存储过程与Oracle存储过程的代码格式比较
Sql定义存储过程方式:
CREATE PROCEDURE SP_NAME
(参数1 IN/OUT 类型(长度), --这里的长度是指像VARCHAR(20)这样的类型,
而如果是INT就不需要了
参数2 IN/OUT 类型(长度)...)
AS
BEGIN
--变量声明
DECLARE @变量1 类型(长度)
@变量2 类型(长度)
......
--临时表声明
--变量初始化
SELECT @变量1 = ?
@变量2 = ?
......
--游标声明
--逻辑处理
--异常处理
END
Oracle定义存储过程方式:
CREATE OR REPLACE PROCEDURE SP_NAME(
S_参数1 IN/OUT 类型, --类型不允许带长度,如不允许写VARCHAR2(20),
只能写VARCHAR2,是与sql不同的一个地方
S_参数2 IN/OUT 类型......,
RCT1 OUT PACKAGE_FRTNET.refCursor, --结果集输出统一使用游标,只能为OUT
RCT2 OUT PACKAGE_FRTNET.refCursor......
)
AS
--变量声明,Oracle变量声明全部放在这个位置,是与sql不同的第二个地方
V_变量1 类型(长度);
V_变量2 类型(长度);
......;
--游标初始化
CURSOR CUR_游标名 IS SELECT ......;
BEGIN
--变量初始化
V_变量1 := ?;
V_变量2 := ?;
......;
BEGIN
--逻辑处理
EXCEPTION
WHEN OTHERS THEN
--异常处理
END;
END SP_NAME;
4.4.2 原Sql临时表中有自增字段的处理方式
原Sql存储过程中临时表包含自增字段:
CREATE TABLE #TEMPTABLE
(CODE INT IDENTITY ,
CUST_ID NVARCHAR(40))
INSERT INTO #TEMPTABLE(CUST_ID)
SELECT CUST_ID FROM SB_CREDIT_CUSOTMER
GROUP BY CUST_ID
比如遇到以上有自增字段的临时表,在Oracle使用嵌套子查询的方式解决:
CREATE GLOBAL TEMPORARY TABLE TMP_OZ_SEARCH_CREDIT
(
CODE INT,
CUST_ID NVARCHAR2 (40)
)
ON COMMIT DELETE ROWS;
INSERT INTO TMP_OZ_SEARCH_CREDIT(CODE,CUST_ID)
SELECT ROWNUM,CUST_ID FROM
(SELECT CUST_ID
FROM SB_CREDIT_CUSOTMER
GROUP BY CUST_ID);
4.4.3 Sql中使用Top N 语句在Oracle中的处理方式
原sql语句使用Top N:
SELECT TOP 30 SELECT A.BK_PANEL_ID, A.BK_PANEL_NO, A.FLIGHT_NO, A.CARRIER_CODE, A.POD_CODE, A.FLIGHT_TIME
FROM AIR_BK_PANEL AS A --注意:在Oracle中给表定义表别名时,不允许使用AS
WHERE A.FLIGHT_NO LIKE '1%'
ORDER BY A.FLIGHT_TIME DESC
比如以上的sql语句,在Oracle使用嵌套子查询的方式解决:
SELECT BK_PANEL_ID, BK_PANEL_NO, FLIGHT_NO, CARRIER_CODE, POD_CODE, FLIGHT_TIME
FROM (SELECT A.BK_PANEL_ID, A.BK_PANEL_NO, A.FLIGHT_NO, A.CARRIER_CODE, A.POD_CODE, A.FLIGHT_TIME FROM AIR_BK_PANEL A --直接在表后面跟上表别名,不允许使用AS
WHERE A.FLIGHT_NO LIKE '1%' ORDER BY FLIGHT_TIME DESC)
WHERE ROWNUM <=30
说明:想了解更多的ROWNUM的使用可以参见:
http://blog.csdn.net/zhenyucheung/archive/2008/05/15/2449954.aspx
4.4.4 Sql中使用UPDATE FROM 语句在Oracle中的处理方式
原sql语句使用UPDATE FROM:
UPDATE #AIRBKHEADER
SET SHIPPER = B.PARTNER_ID ,CONSIGNEE_NAME = B.CONSIGNEE_NAME
FROM #AIRBKHEADER AS A
JOIN AIR_BK_PARTNER AS B ON A.JOB_ORDER_ID = B.JOB_ORDER_ID
WHERE A.IO_ID = 'O' AND B.PARTNER_TYPE = 'SH'
比如以上的sql语句,在Oracle有一下两种解决方案:
方案一:使用游标(不推荐使用)
CURSOR G1_CURSOR IS
SELECT R.ROWID ,B.PARTNER_ID, B.CONSIGNEE_NAME
FROM TMP_AIR_ARRANGE_TRUCK A, AIR_BK_PARTNER B
WHERE A.JOB_ORDER_ID = B.JOB_ORDER_ID AND A.IO_ID = 'O' AND B.PARTNER_TYPE = 'SH';
OPEN G1_CURSOR;
LOOP
FETCH G1_CURSOR INTO G1_ROWID,G1_COL1,G1_COL2;
EXIT WHEN G1_CURSOR%NOTFOUND;
BEGIN
UPDATE TEM_AIR_BKHEADER
SET SHIPPER = G1_COL1, CONSIGNEE_NAME = G1_COL2
WHERE ROWID = G1_ROWID;
END;
END LOOP;
CLOSE G1_CURSOR;
方案二:使用子查询(翻译过程中尽量使用该方法,除非该方法行不通才考虑使用游标)
UPDATE TMP_AIR_ARRANGE_TRUCK A SET (SHIPPER,CONSIGNEE_NAME) =
(SELECT B.PARTNER_ID,B.CONSIGNEE_NAME
FROM AIR_BK_PARTNER B
WHERE B.JOB_ORDER_ID = A.JOB_ORDER_ID
AND B.PARTNER_TYPE = 'SH')
WHERE A.IO_ID = 'O' AND
EXISTS(SELECT 1 FROM AIR_BK_PARTNER C WHERE
C.JOB_ORDER_ID = A.JOB_ORDER_ID AND C.PARTNER_TYPE = 'SH');
4.4.5 事物临时表和会话临时表的区别和注意事项
可参见文章:
Oracle临时表的使用:
http://blog.csdn.net/yuzhic/archive/2008/01/20/2054491.aspx
Oracle数据库临时表管理心得:
http://www.bitscn.com/oracle/exploiture/200806/144601_2.html
4.4.6 对原Sql分页在Oracle中处理
原sql的处理方式:
方式一:使用包含自增字段的临时表处理分页
DECLARE
@PAGENUM INT,
@PAGESIZE INT
BEGIN
CREATE TABLE #AIRBKHEADER (NUM INT IDENTITY,
JOB_ORDER_ID NVARCHAR(20),
HAWB_NO NVARCHAR(20),
MAWB_NO NVARCHAR(20) )
CREATE TABLE #AIRBKHEADERTEMP (JOB_ORDER_ID NVARCHAR(20),
HAWB_NO NVARCHAR(20),
MAWB_NO NVARCHAR(20) )
INSERT #AIRBKHEADERTEMP(JOB_ORDER_ID,HAWB_NO,MAWB_NO)
SELECT A.JOB_ORDER_ID,A.HAWB_NO,A.MAWB_NO
FROM AIR_BK_HEADER A LEFT JOIN VW_AIRBK_PARTNER B
ON A.JOB_ORDER_ID = B.JOB_ORDER_ID ORDER BY A.JOB_ORDER_ID
INSERT #AIRBKHEADER(JOB_ORDER_ID,HAWB_NO,MAWB_NO)
SELECT * FROM #AIRBKHEADERTEMP
SET @FIRSTRECORDNUM = (@PAGENUM - 1) * @PAGESIZE + 1
SELECT NUM,JOB_ORDER_ID,HAWB_NO,MAWB_NO
FROM #AIRBKHEADER WHERE NUM >= @FIRSTRECORDNUM AND NUM < @FIRSTRECORDNUM + @PAGESIZE
END
方式二:使用Top N 处理分页
SELECT TOP @PAGE_SIZE JOB_ORDER_ID,HAWB_NO,MAWB_NO FROM AIR_BK_HEADER
WHERE JOB_ORDER_ID NOT IN
(SELECT TOP (@PAGESIZE*(@PAGEINDEX-1)) JOB_ORDER_ID FROM AIR_BK_HEADER)
Oracle处理方式:
方式一:使用临时表处理分页
CREATE GLOBAL TEMPORARY TABLE TMP_AIR_ARRANGE_TRUCK
(NUM INTEGER,
JOB_ORDER_ID VARCHAR2(20),
BK_NO VARCHAR2(20),
MAWB_NO VARCHAR2(20))
ON COMMIT DELETE ROWS;
INSERT INTO TMP_AIR_ARRANGE_TRUCK(NUM,JOB_ORDER_ID,BK_NO,MAWB_NO)
SELECT ROWNUM,JOB_ORDER_ID,BK_NO,MAWB_NO FROM
(SELECT A.JOB_ORDER_ID,A.BK_NO,A.MAWB_NO
FROM AIR_BK_HEADER A LEFT JOIN VW_AIRBK_PARTNER B
ON A.JOB_ORDER_ID = B.JOB_ORDER_ID ORDER BY A.JOB_ORDER_ID) ;
--遇到ORDER BY 或者 GROUD BY 或者 DISTINCT 关键字一定要再嵌套一次,不建议直接写成:
INSERT INTO TMP_AIR_ARRANGE_TRUCK(NUM,JOB_ORDER_ID,BK_NO,MAWB_NO)
SELECT ROWNUM, A.JOB_ORDER_ID,A.BK_NO,A.MAWB_NO
FROM AIR_BK_HEADER A LEFT JOIN VW_AIRBK_PARTNER B
ON A.JOB_ORDER_ID = B.JOB_ORDER_ID ORDER BY A.JOB_ORDER_ID;
最后进行分页:
V_FIRSTRECORDNUM = (V_PAGENUM - 1) * V_PAGESIZE + 1;
SELECT NUM,JOB_ORDER_ID,HAWB_NO,MAWB_NO
FROM TMP_AIR_ARRANGE_TRUCK WHERE NUM >= V_FIRSTRECORDNUM AND NUM < V_FIRSTRECORDNUM + V_PAGESIZE;
方式二:使用ROWNUM处理分页
情景一:
SELECT COLS FROM
(SELECT ROWNUM R_N, COLS
FROM TABLE_NAME
WHERE FILTERS AND ROWNUM <= V_PAGEINDEX * V_PAGESIZE ) T
WHERE T.R_N > (V_PAGEINDEX - 1) * V_PAGESIZE;
情景二:
V_FIRSTRECORDNUM := (V_PAGEINDEX - 1) * V_PAGESIZE + 1;
SELECT COLS FROM
(SELECT ROWNUM R_N, COLS
FROM TABLE_NAME
WHERE FILTERS AND ROWNUM < V_FIRSTRECORDNUM + V_PAGESIZE) T
WHERE T.R_N >= V_FIRSTRECORDNUM;
4.4.7 输入参数的处理
对于输入参数我们一般做如下处理:
CREATE OR REPLACE PROCEDURE SPAIR_LIST_BOOKING_PANEL
(
S_FILTERSTR IN VARCHAR2 DEFAULT NULL,
RCT1 OUT PACKAGE_FRTNET.REFCURSOR
)
AS
V_FILTERSTR VARCHAR2(2000) := S_FILTERSTR;
V_INDEX INTEGER;
V_START INTEGER;
V_SUBSTRING VARCHAR2(2000);
V_UNITSTART INTEGER;
V_FIELDNAME VARCHAR2(2000);
V_FIELDVALUE VARCHAR2(2000);
BEGIN
V_START := 1;
V_FILTERSTR := TRIM(V_FILTERSTR);
WHILE(V_FILTERSTR IS NOT NULL) LOOP
BEGIN
V_INDEX := INSTR(V_FILTERSTR,';',V_START);
IF(V_INDEX = 0) THEN
BEGIN
V_SUBSTRING := SUBSTR(V_FILTERSTR,V_START,LENGTH(V_FILTERSTR) - V_START +1);
END;
ELSE
BEGIN
V_SUBSTRING := SUBSTR(V_FILTERSTR,V_START,V_INDEX - V_START);
END;
END IF;
V_UNITSTART := 1;
V_UNITINDEX := INSTR(V_SUBSTRING,'|',V_UNITSTART);
V_FIELDNAME := UPPER(SUBSTR(V_SUBSTRING,V_UNITSTART,V_UNITINDEX-V_UNITSTART));
--对于V_FIELDNAME一定要进行UPPER操作
V_FIELDVALUE := SUBSTR(V_SUBSTRING,V_UNITINDEX+1,LENGTH(V_SUBSTRING));
IF V_FIELDNAME = 'ISALLOCATION' THEN
BEGIN
V_ISALLOCATION := V_FIELDVALUE;
END;
END IF;
IF(V_INDEX = 0) THEN
BEGIN
EXIT;
END;
END IF;
V_START := V_INDEX + 1;
END;
END LOOP;
END;
说明:1.V_FILTERSTR VARCHAR2(2000) := S_FILTERSTR;
这步处理因为输入参数不允许对本身进行值变更操作,如下列使用有误:
S_FILTERSTR := TRIM (S_FILTERSTR);但是输出参数允许这样操作。
2.V_FIELDNAME := UPPER(SUBSTR(V_SUBSTRING,V_UNITSTART,V_UNITINDEX-V_UNITSTART));
这步操作是因为后面的比较字段为大写的,为防止输入参数可能为小写的情况发生,对于
V_FIELDNAME必须进行UPPER操作。
4.4.8 原Sql中空和非空的判断的处理
原sql的空判断:
DECLARE @A VARCHAR(20)
SET @A = NULL
IF (ISNULL(@A,'') = '')
PRINT 'A'
ELSE
PRINT 'B'
或者 SET @A = '',以上的执行结果都是打印出: A
但是对于Oracle来说不允许使用以上方式做非空判断,因为
DECLARE V_A VARCHAR2(20) := NULL ;
BEGIN
IF (NVL(V_A,'') = '') THEN
DBMS_OUTPUT.put_line('A');
ELSE
DBMS_OUTPUT.put_line('B');
END IF;
END;
或者 DECLARE V_A VARCHAR2(20) := '' ;
以上的执行结果都是打印出: B
同理在对非空判断也不允许使用(NVL(V_A,'') <> '')
总之:在Oracle中,对于空和非空的判断只允许使用 V_A IS NULL 或者 V_A IS NOT NULL
因为在Oracle中 '' 也就是 NULL ,NULL跟任何数做比较(不管是 =、<>、>、<)
作为判断条件都为False
4.4.9 原Sql的左连接
原sql语句:
SELECT B.MBL_NO, B.HBL_NO, B.BL_TYPE, LINE_NAME = C.ABBREV, A.CONTAINER_NO,
A.SEAL_NO, A.CONTAINER_SIZE_TYPE, A.CONTAINER_STATUS
FROM OZ_BK_CONTAINER AS A
JOIN #BKHEADER AS TMP ON (TMP.JOB_ORDER_ID = A.JOB_ORDER_ID)
LEFT JOIN OZ_BK_HEADER AS B ON A.JOB_ORDER_ID = B.JOB_ORDER_ID
LEFT JOIN OB_LINE AS C ON B.LINEDEF_ID = C.LINEDEF_ID
ORACLE除了以上写法外还有另外一种独有的写法:
SELECT B.MBL_NO,B.HBL_NO,B.BL_TYPE,C.ABBREV LINE_NAME,A.CONTAINER_NO,A.SEAL_NO,
A.CONTAINER_SIZE_TYPE,A.CONTAINER_STATUS
FROM OZ_BK_CONTAINER A,TMP_OZ_HEADER_SESSION TMP,OZ_BK_HEADER B,OB_LINE C
WHERE (TMP.JOB_ORDER_ID = A.JOB_ORDER_ID)
AND (A.JOB_ORDER_ID = B.JOB_ORDER_ID (+))
AND (B.LINEDEF_ID = C.LINEDEF_ID (+));
4.4.10 动态语句的执行
原sql方式:
DECLARE @USER_NAME='XIAO'
EXEC 'SELECT * FROM SB_USER WHERE USR_NAME LIKE'''+@USER_NAME+'%'''
Oracle处理方式:
V_USER_NAME :='XIAO';
EXECUTE IMMEDIATE 'SELECT * FROM USER WHERE USR_NAME LIKE''' || V_USER_NAME || '%''';
建议:尽量避免使用动态语句,以提高性能
4.4.11 Oracle中结果集游标使用的注意事项
首先看下面的例子:
CREATE OR REPLACE PROCEDURE SP_S_CITY_SEARCH
(
S_FILTERSTR IN VARCHAR2,
S_RECORDCOUNT OUT INT,
RCT1 OUT PACKAGE_FRTNET.REFCURSOR,
RCT2 OUT PACKAGE_FRTNET.REFCURSOR
) AS
V_STARTRECORD INT := 1;
BEGIN
OPEN RCT1 FOR
SELECT A.* FROM SB_CITY A
JOIN TMP_COM_TLBCITY B ON (A.CITY_ID = B.CITY_ID)
WHERE B.NUM >= V_STARTRECORD AND B.NUM < V_MAXRECORDS + V_STARTRECORD;
IF V_STARTRECORD := 0 THEN
OPEN RCT2 FOR
SELECT S_RECORDCOUNT FROM DUAL;
END IF;
END;
对于以上情况 当 IF 条件不成立时,游标RCT2 在Oracle测试用例中将报以下错误。
该错误是会抛到我们freightnet客户端的。错误信息为:
"ORA-06550: 第 1 行, 第 7 列: "nPLS-00306: 调用 'SP_S_CITY_SEARCH' 时参数个数或类型错误"nORA-06550: 第 1 行, 第 7 列: "nPL/SQL: Statement ignored"
或者:
"未将对象引用设置到对象的实例。"
于是我们做如下规定:遇到类似上面的IF语句,我们这样处理:
IF V_STARTRECORD := 0 THEN
OPEN RCT2 FOR
SELECT S_RECORDCOUNT FROM DUAL;
ELSE
OPEN RCT2 FOR
SELECT * FROM DUAL;
END IF;
注意这里统一使用 SELECT * FROM DUAL; 因为该语句返回的结果是:
低层框架会自动过滤 包含DUMMY字段的表,使之返回的整个DataSet与Sql版本一致。
同时这里再强调下:
对于Oracle中的每个返回结果集的 游标一定要使用到(也就是千万不要出现“未执行语句句柄”bug),如果没使用到千万不要定义,或者因条件不成立而没执行的结果集游标就按上面的方法进行处理,让它返回字段名为:DUMMY的表,让框架自动过滤掉该表!
还有要防止结果集游标的滥用,我们看如下的例子其实只需定义一个返回结果集游标即可。
CREATE OR REPLACE PROCEDURE SP_S_TEST
(
S_OFFICEID IN VARCHAR2,
S_SYSTEMNO IN VARCHAR2,
RCT1 OUT PACKAGE_FRTNET.REFCURSOR
) AS
V_HASOFFICE INTEGER;
V_SYSTEMNOCOUNT INTEGER;
V_SELECTSTRING VARCHAR(4000);
BEGIN
SELECT COUNT(1) INTO V_HASOFFICE FROM SB_OFFICE;
IF (V_HASOFFICE <= 0) THEN
BEGIN
OPEN RCT1 FOR SELECT * FROM TABLE1;
RETURN;
END;
ELSE
BEGIN
OPEN RCT1 FOR SELECT * FROM DUAL;
RETURN;
END;
END IF;
IF (S_SYSTEMNO IS NULL) THEN
IF (V_SYSTEMNOCOUNT > 0) THEN
OPEN RCT1 FOR SELECT * FROM TABLE2;
ELSE
OPEN RCT1 FOR SELECT * FROM TABLE3;
END IF;
ELSE
IF (V_SYSTEMNOCOUNT > 0) THEN
OPEN RCT1 FOR SELECT * FROM TABLE4;
ELSE
OPEN RCT1 FOR SELECT * FROM TABLE5;
END IF;
END IF;
END;
4.4.12 触发器使用注意事项
现在我们整个FR系统使用的Oracle数据库的触发器主要用于包含时间戳字段的表。
我们约定如果某个表包含时间戳字段,那么该字段名称为:TIMESTAMP。
同时为该表建立如下统一格式的触发器:
CREATE OR REPLACE TRIGGER TR_TABLENAME
BEFORE INSERT OR UPDATE ON TABLENAME
FOR EACH ROW
BEGIN
IF INSERTING THEN
:NEW.TIMESTAMP := 0;
ELSE
:NEW.TIMESTAMP := :OLD.TIMESTAMP + 1;
END IF;
END;
4.4.13 使用GOTO语句替换SQL的CONTINUE语句
由于Oracle中不能使用CONTINUE语句,类似于SQL中的CONTINUE则转化为GOTO语句
原SQL处理方式:
DECLARE @V_NUM INT
DECLARE @V_SUM INT
SELECT @V_NUM = 1,@V_SUM =0;
BEGIN
WHILE @V_NUM <= 4
BEGIN
IF (@V_NUM = 3)
BEGIN
SET @V_NUM = @V_NUM + 1;
CONTINUE
END
SET @V_SUM = @V_SUM + @V_NUM;
PRINT(@V_NUM);
IF @V_NUM < 4
BEGIN
PRINT('+');
END
SET @V_NUM = @V_NUM + 1;
END;
PRINT('=');
PRINT(@V_SUM);
END;
现Oracle处理方式:
DECLARE
V_NUM INTEGER := 1;
V_SUM INTEGER := 0;
BEGIN
<<LABEL1>>
WHILE V_NUM <= 4 LOOP
IF V_NUM = 3 THEN
V_NUM := V_NUM + 1;
GOTO LABEL1;
END IF;
V_SUM := V_SUM + V_NUM;
DBMS_OUTPUT.PUT_LINE(V_NUM);
IF V_NUM < 4 THEN
DBMS_OUTPUT.PUT_LINE('+');
END IF;
V_NUM := V_NUM + 1;
END LOOP;
DBMS_OUTPUT.PUT_LINE('=');
DBMS_OUTPUT.PUT_LINE(V_SUM);
END;
4.4.14 其他注意事项
1.Oracle没有 WITH(NOLOCK)
2.对于插入语句Sql中允许使用 INSERT "INSERT INTO,
但Oracle中只允许使用INSERT INTO
3.Sql的系统表为: SYSOBJECTS ,Oracle的系统表为: DBA_OBJECTS
4.Oracle不允许有dbo.表名的使用
5. SQL的跳出循环使用的关键字为:BREAK,ORACLE跳出循环使用的关键字为:EXIT
6.执行DROP TABLE TBALENAME 和 TRUNCATE TABLE TBALENAME 时,
默认帮你执行了COMMIT,所以在使用事务级别的临时表时要小心
7.原来SQL的 CHAR(10)和 CHAR(13) 在ORACLE中为 CHR(10) 和 CHR(13)
8.sql的@@Rowcount全局变量,在Oracle则是用SQL%ROWCOUNT
9.sql中的GOTO的标签格式为: LABEL: ,Oracle的GOTO的标签格式为: <<LABEL>>
调用标签后的语句都为 GOTO LABEL;
10.动态给变量赋值:
DECLARE
V_COUNT INT;
V_USERID VARCHAR2(50);
BEGIN
EXECUTE IMMEDIATE 'SELECT COUNT(*), MAX(USR_ID) FROM SB_USER ' INTO V_COUNT,V_USERID;
DBMS_OUTPUT.PUT_LINE(V_COUNT || V_USERID);
END;
11.绑定变量的使用:
DECLARE
V_USERNAME VARCHAR2(50);
V_ID VARCHAR2(50):= '073C0OY3760H0';
BEGIN
EXECUTE IMMEDIATE 'SELECT USR_NAME FROM SB_USER WHERE USR_ID = :ID' INTO V_USERNAME USING V_ID ;
DBMS_OUTPUT.PUT_LINE(V_USERNAME);
END;
12.如果存储过程中包含临时表,最好在 AS BEGIN 后进行所有临时表数据清空操作。防止事务或者会话没控制好未让Oracle自动清除临时表数据,导致两次调用存储过程,临时表数据累加的情况出现。
如:
CREATE OR REPLACE PROCEDURE SP_NAME
( S_PARA1 IN VARCHAR2,
S_PARA2 IN VARCHAR2,
RCT1 OUT PACKAGE_FRTNET.refCursor )
AS
V_VARIABLE1 VARCHAR2(20);
BEGIN
DELETE FROM TMP_MODULE_TEMPTABLENAME;
INSERT INTO TMP_MODULE_TEMPTABLENAME SELECT COL1,COL2,COL3 FROM SB_TABLE;
OPEN RCT1 FOR SELECT TMP_MODULE_TEMPTABLENAME;
END SP_NAME;
13.对于以下情况的存储过程要注意结果集输出语句写法
CREATE OR REPLACE PROCEDURE SP_OZ_ACCESSORIES_LIST
(S_FILTERSTR_IN IN VARCHAR2,
S_ROLEID IN VARCHAR2,
S_USERID IN VARCHAR2,
RCT1 OUT PACKAGE_FRTNET.REFCURSOR )
AS
V_RECORDCOUNT INTEGER;
BEGIN
SP_FILTER_DATARIGHT_X(S_ROLEID,
S_USERID,
'OZ_BK_HEADER',
'CC',
'QUERY',
V_ROLECONDITION); --调用其他存储过程的用法
IF (V_ROLECONDITION IS NULL) THEN
BEGIN
V_ROLECONDITION := '(1=1)';
END;
END IF;
SELECT COUNT(BLACC_ID) INTO V_RECORDCOUNT FROM TMP_OZ_ACCESSORY_BLACC_ID WHERE || V_ROLECONDITION;
OPEN RCT1 FOR SELECT V_RECORDCOUNT FROM DUAL;
END;
以上结果集输出为: ,但是列名为 :B1 返回到Appserver端无法识别该列名将抛出异常。
我们必须要输出语句改为:
OPEN RCT1 FOR 'SELECT''' || V_RECORDCOUNT || ''' AS COLCOUNT FROM DUAL';
也就是说V_RECORDCOUNT是变量,必须使用动态Sql语句。这样的结果集输出为: