• 博客园logo
  • 会员
  • 众包
  • 新闻
  • 博问
  • 闪存
  • 赞助商
  • HarmonyOS
  • Chat2DB
    • 搜索
      所有博客
    • 搜索
      当前博客
  • 写随笔 我的博客 短消息 简洁模式
    用户头像
    我的博客 我的园子 账号设置 会员中心 简洁模式 ... 退出登录
    注册 登录
西门吹雪
非我伤春春伤我,风一阵,雨一阵,好景不在哀残痕。 非我厌世世厌我,闲言来,碎语去,红颜憔悴心头冷。
博客园    首页    新随笔    联系   管理    订阅  订阅

从SQL SERVER 向ORACLE 8迁移的技术实现方案(3)

在程序中,三次定义同一游标cur_yp   在迁移过程中,最好先定义一游标变量,在程序中用open打开,如下: declare type cur_type is ref cur_type; cur_yp cur_type; … begin open cur_yp for select * from yp; loop fetch cur_yp into yp,mc … Exit When cur_yp%NotFound; …. end loop; close cur_yp; open cur_yp for select * from yp where condition1; loop fetch cur_yp into yp,mc … Exit When cur_yp%NotFound; …. end loop; close cur_yp; open cur_yp for select * from yp where condition2; loop fetch cur_yp into yp,mc … Exit When cur_yp%NotFound; …. end loop; close cur_yp; end;   (7)请注意,游标循环中中一定要退出语名,要不然执行时会出现死循环。   返回首页   <五> 存储过程/函数   <1>、SQL SERVER端语法说明   1、语法: CREATE PROC[EDURE] [owner.]procedure_name [;number] [ (parameter1[, parameter2]…[, parameter255])] [ {FOR REPLICATION} | {WITH RECOMPILE} [ {[WITH] | [ , ] } ENCRYPTION ] ] AS sql_statement [...n]   其中,Parameter = @parameter_name datatype [=default] [output]   说明:T-SQL中存储过程的结构大致如下 CREATE PROCEDURE procedure_name /*输入、输出参数的声明部分*/ AS DECLARE /*局部变量的声明部分*/ BEGIN /*主体SQL语句部分*/ /*游标声明、使用语句在此部分*/ END 2、示例: IF EXISTS(SELECT 1 FROM sysobjects WHERE name = 'titles_sum' AND type = 'P') DROP PROCEDURE titles_sum GO CREATE PROCEDURE titles_sum @TITLE varchar(40) = '%', @SUM money OUTPUT AS BEGIN SELECT 'Title Name' = title FROM titles WHERE title LIKE @TITLE SELECT @SUM = SUM(price) FROM titles WHERE title LIKE @TITLE END   <2>、ORACLE端PROCEDURE语法说明   1、语法: CREATE [OR REPLACE] PROCEDURE procedure_name [ (parameter1 [ {IN | OUT | IN OUT } ] type , … parametern [ {IN | OUT | IN OUT } ] type ) ] { IS | AS } [BEGIN] sql_statement [...n] ; [END] ;   说明:PL/SQL中存储过程的结构大致如下 CREATE OR REPLACE PROCEDURE procedure_name ( /*输入、输出参数的声明部分*/ ) AS /*局部变量、游标等的声明部分*/ BEGIN /*主体SQL语句部分*/ /*游标使用语句在此部分*/ EXCEPTION /*异常处理部分*/ END ;   2、示例: CREATE OR REPLACE PROCEDURE drop_class ( arg_student_id IN varchar2, arg_class_id IN varchar2, status OUT number ) AS counter number ; BEGIN status := 0 ; -- Verify that this class really is part of the student’s schedule. select count (*) into counter from student_schedule where student_id = arg_student_id and class_id = arg_class_id ; IF counter = 1 THEN delete from student_schedule where student_id = arg_student_id and class_id = arg_class_id ; status := -1 ; END IF ; END ; <3>ORACLE端FUNCTION语法说明   (1) 语法 CREATE [OR REPLACE] FUNCTION function_name [(argument [{IN | OUT | IN OUT }] ) type, … [(argument [{IN | OUT | IN OUT }] ) type RETURN return_type {IS | AS} BEGIN … END;   关键字return 指定了函数返回值的数据类型。它可以是任何合法的PL/SQL数据类型。每个函数都必须有一个return 子句,因为在定义上函数必须返回一个值给调用环境。   (2)示例 CREATE OR REPLACE FUNCTION blanace_check(Person_Name IN varchar2) RETURN NUMBER IS Balance NUMBER(10,2); BEGIN Select sum(decode(acton,’BOUGHT’,Amount,0)) INTO balance FROM ledger WHERE Person = Person_name; RETURN (balance); END;   (3)过程与函数的区别   函数可以返回一个值给调用环境;而过程不能,过程只能通过返回参数(带“OUT”或“IN OUT”)传回去数据。   <4>从SQL SERVER向ORACLE的迁移方案   通过比较上述SQL语法的差异,在迁移时必须注意以下几点:   1、对于有返回单值的MSSQL存储过程,在数据库移值最好转换成ORALCE的函数;对于MSSQL有大量数据的处理而又不需返回值的存储过程转换成ORACLE的过程   2、在T-SQL中,输入、输出参数定义部分在“CREATE…”和“AS”之间,前后   没有括号;而在PL/SQL中必须有“(”和“)”与其他语句隔开。   3、在T-SQL中,声明局部变量时,前面要有DECLARE关键字; 而在PL/SQL中不用DECLARE关键字。   4、在T-SQL中,参数名的第一个字符必须是“@”,并符合标识符的规定;   而在PL/SQL中,参数名除符合标识符的规定外没有特殊说明,T-SQL中,对于参数可其数据类型及其长度和精度;但是PL/SQL中除了引用%TYPE和%ROWTYPE之外,不能在定义参数数据类型时给出长度和精度,如下: CREATE OR REPLACE PROCEDURE PROC_SELE_YS (YSDM CHAR(6),GZ NUMBER(14,4)) AS BEGIN … END;   是错误的,应如下定义 CREATE OR REPLACE PROCEDURE PROC_SELE_YS (YSDM CHAR,GZ NUMBER) AS BEGIN … END;   或者 CREATE OR REPLACE PROCEDURE PROC_SELE_YS (YSDM YSDMB.YSDM%TYPE,GZ YSDMB.GZ%TYPE) AS BEGIN … END;   5、对于T-SQL,游标声明在主体SQL语句中,即声明与使用语句同步;   而在PL/SQL中,游标声明在主体SQL语句之前,与局部变量声明同步。   6、对于T-SQL,在主体SQL语句中用如下语句对局部变量赋值(初始值或   数据库表的字段值或表达式):   “SELECT 局部变量名 = 所赋值(初始值或数据库表的字段值或表达式)”;   而在PL/SQL中,将初始值赋给局部变量时,用如下语句:   “局部变量名 : = 所赋值(初始值或表达式);” ,   将检索出的字段值赋给局部变量时,用如下语句:   “SELECT 数据库表的字段值 INTO 局部变量名 …” 。   7、在PL/SQL中,可以使用%TYPE来定义局部变量的数据类型。说明如下:   例如,students表的first_name列拥有类型VARCHAR2(20),基于这点, 我们可以按照下述方式声明一个变量:   V_FirstName VARCHAR2(20) ;   但是如果改变了first_name列的数据类型则必须修改该声明语句,因此可以采   用%TYPE进行变量数据类型声明:   V_FirstName students.first_name%TYPE ;   这样,该变量在存储过程编译时将由系统自动确定其相应数据类型。   8、对于T-SQL,没有定义语句结束标志,而PL/SQL用“END <过程名>;”结束语句。   9、存储过程的调用要注意:在MSSQLSERVER中的格式为“EXEC Procedure_Name {arg1,arg2,…},但在ORACLE中直接引用过程名即可,如要执行存储过程DefaltNo,其参数为“9”,则执行时为 Default(“9”)。   10、ORACLE 数据库的存储过程不支持用select 子句直接返回一个数据集,要做到通过程产生一记录集有两种方案:   方案一:采用包和游标变量   第一步,创建一个包,定义一个游标变量 create package p_name is type cursor_name is ref cursor; end;   第二步,创建过程,但是基返回参数用包中的游标类型 create procedure procedure_name(s in out p_name.cursor_name) is begin open s for select * from table_name...; end;   这样,通过存储过程就可以返回一个数据集了,但用到这种情况,过程的参数中只这返回结果的游标参数可以带关键字”OUT”,其它不能带”out”,否则,系统会出现导常。   方案二:通过中间表,建一中间表,其表格的列为所需数据列再加上一个序列字段。过程的处理为将数据插入到中间表中,同时通过   select userenv(‘sessionid’) from dual;取得当前连接会话的序号,将取得的序号值放置到序列字段中,同时存储过程返回连接会话的序号,前台PB程序直接访问中间表,数据窗口在检索时通过序号参数可将所需的数据检索出来。 <六> 触发器   <1>、SQL SERVER端语法说明   1、语法: CREATE TRIGGER [owner.]trigger_name ON [owner.]table_name FOR { INSERT, UPDATE, DELETE } [WITH ENCRYPTION] AS sql_statement [...n]   或者使用IF UPDATE子句: CREATE TRIGGER [owner.]trigger_name ON [owner.]table_name FOR { INSERT, UPDATE } [WITH ENCRYPTION] AS IF UPDATE (column_name) [{AND | OR} UPDATE (column_name)…] sql_statement [ ...n]   2、示例: IF EXISTS (SELECT 1 FROM sysobjects WHERE name = 'reminder' AND type = 'TR') DROP TRIGGER reminder GO CREATE TRIGGER employee_insupd ON employee FOR INSERT, UPDATE AS /* Get the range of level for this job type from the jobs table. */ DECLARE @min_lvl tinyint, @max_lvl tinyint, @emp_lvl tinyint, @job_id smallint SELECT @min_lvl = min_lvl, @max_lvl = max_lvl, @emp_lvl = i.job_lvl, @job_id = i.job_id FROM employee e, jobs j, inserted i WHERE e.emp_id = i.emp_id AND i.job = j.job_id IF (@job_id = 1) and (@emp_lvl <> 10) BEGIN RAISERROR ('Job id 1 expects the default level of 10.', 16, 1) ROLLBACK TRANSACTION END ELSE IF NOT (@emp_lvl BETWEEN @min_lvl AND @max_lvl) BEGIN RAISERROR ('The level for job_id:%d should be between %d and %d.', 16, 1, @job_id, @min_lvl, @max_lvl) ROLLBACK TRANSACTION END GO <2>、ORACLE端语法说明   1、语法: CREATE [OR REPLACE] TRIGGER trigger_name { BEFORE | AFTER } triggering_event ON table_name [ FOR EACH ROW ] [ WHEN trigger_condition ] trigger_body ;   2、使用说明与示例:   (1)、上语法中,trigger_event 是对应于DML的三条语句INSERT、UPDATE、   DELETE;table_name是与触发器相关的表名称;FOR EACH ROW是可选   子句,当使用时,对每条相应行将引起触发器触发;condition是可选的   ORACLE BOOLEAN条件,当条件为真时触发器触发;trigger_body是触发   器触发时执行的PL/SQL块。   (2)、ORACLE触发器有以下两类:   1> 语句级(Statement-level)触发器,在CREATE TRIGGER语句中不   包含FOR EACH ROW子句。语句级触发器对于触发事件只能触发一次,   而且不能访问受触发器影响的每一行的列值。一般用语句级触发器处理   有关引起触发器触发的SQL语句的信息——例如,由谁来执行和什么时   间执行。   2> 行级(Row-level)触发器,在CREATE TRIGGER语句中   包含FOR EACH ROW子句。行级触发器可对受触发器影响的每一行触   发,并且能够访问原列值和通过SQL语句处理的新列值。行级触发器的   典型应用是当需要知道行的列值时,执行一条事务规则。   (3)在触发器体内,行级触发器可以引用触发器触发时已存在的行的列值,这些   值倚赖于引起触发器触发的SQL语句。   1> 对于INSERT语句,要被插入的数值包含在new.column_name,这里的   column_name是表中的一列。   2> 对于UPDATE语句,列的原值包含在old.column_name中,数据列的新   值在new.column_name中。   3> 对于DELETE语句,将要删除的行的列值放在old.column_name中。   触发语句   :old   :new   INSERT   无定义——所有字段都是NULL   当该语句完成时将要插入的数值   UPDATE   在更新以前的该行的原始取值   当该语句完成时将要更新的新值   DELETE   在删除行以前的该行的原始取值   未定义——所有字段都是NULL   4> 在触发器主体中,在new和old前面的“:”是必需的。而在触发器的   WHEN子句中,:new和:old记录也可以在WHEN子句的condition内部   引用,但是不需要使用冒号。例如,下面CheckCredits触发器的主体仅   当学生的当前成绩超过20时才会被执行: CREATE OR REPLACE TRIGGER CheckCredits BEFORE INSERT OR UPDATE OF current_credits ON students FOR EACH ROW WHEN (new.current_credits > 20) BEGIN /*Trigger body goes here. */ END ;   但CheckCredits也可以按下面方式改写: CREATE OR REPLACE TRIGGER CheckCredits BEFORE INSERT OR UPDATE OF current_credits ON students FOR EACH ROW BEGIN IF :new.current_credits > 20 THEN /*Trigger body goes here. */ END IF ; END ;   注意,WHEN子句仅能用于行级触发器,如果使用了它,那么触发器主体   仅仅对那些满足WHEN子句指定的条件的行进行处理。
posted @ 2009-03-12 09:41  西门吹雪  阅读(530)  评论(0)    收藏  举报
刷新页面返回顶部
博客园  ©  2004-2025
浙公网安备 33010602011771号 浙ICP备2021040463号-3