Oracle翻译注意事项

 

 

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的RTRIMLTRIM函数与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用法格式

例子1SELECT  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语句。这样的结果集输出为:

原文地址:https://www.cnblogs.com/kenchell/p/1367433.html