![]() |
|
| 网站首页 | 软件测试论坛 | 软件测试培训 | 软件测试博客 | 软件测试杂志 | 软件测试沙龙 | 软件测试下载 | 软件测试顾问 |
| 业界新闻 | 软件测试人才 | 软件测试技术 | 软件测试工具 | 行业软件测试 | 软件测试管理 | 软件质量专栏 | 软件开发专栏 |
方法: 公司原系统中的Money 用于金额时转换用number(14,2);用于单价时用 number(10,4)代替; <二> ID列向SEQUENCE迁移<1>、SQL SERVER端语法说明 在SQL SERVER中,可以将数据库中的某一字段定义为IDENTITY列以做主键识别,如: jlbh numeric(12,0) identity(1,1) /*记录编号字段*/ CONSTRAINT PK_tbl_example PRIMARY KEY nonclustered (jlbh) /*主键约束*/ 在这里,jlbh是一个ID列,在向具有该列的表插入记录时,系统将从1开始以1的步长自动对jlbh的值进行维护。 <2>、ORACLE端语法说明 但在ORACLE中,没有这样的ID列定义,而是采用另一种方法,即创建SEQUENCE。 如: /*--1、创建各使用地区编码表--*/ drop table LT_AREA; create table LT_AREA ( area_id number(5,0) NOT NULL, /*地区编码*/ area_name varchar2(20) NOT NULL, /*地区名称*/ constraint PK_LT_AREA PRIMARY KEY(area_id) ); /*--2、创建SEQUENCE,将列area_id 类ID化--*/ drop sequence SEQ_LT_AREA; create sequence SEQ_LT_AREA increment by 1 /*该SEQUENCE以1的步长递增*/ start with 1 maxvalue 99999; /*从1开始,最大增长到99999*/ /*--3、实际操作时引用SEQUENCE的下一个值--*/ insert into LT_AREA(area_id, area_name) values(SEQ_LT_AREA.NEXTVAL, '深圳'); insert into LT_AREA(area_id, area_name) values(SEQ_LT_AREA.NEXTVAL, '广州'); insert into LT_AREA(area_id, area_name) values(SEQ_LT_AREA.NEXTVAL, '北京'); /*--4、新插入连续三条记录后,下一条语句运行后,‘上海’地区的area_id为4--*/ insert into LT_AREA(area_id, area_name) values(SEQ_LT_AREA.NEXTVAL, '上海'); <3>、从SQL SERVER向ORACLE的迁移方案 根据以上分析,当从SQL SERVER向ORACLE迁移时,可以做如下调整: 1、去掉建表语句中有关ID列的identity声明关键字; 2、创建SEQUENCE,将此SEQUENCE与需类ID化的列对应; 3、在INSERT语句中对相应列引用其SEQUENCE值:SEQUENCENAME.NEXTVAL 实际上,处理以上情况在ORACLE中采用的方法为对有自动增长字段的表增加一插入前触发器(具体资料见后“触发器”一节),如下: CREATE OR REPLACE TRIGGER GenaerateAreaID BEFORE INSERT ON LT_AREA FOR EACH ROW Select SEQ_LT_AREA.NEXTVAL INTO :NEW.ID FROM DUAL; BEGIN END GenaerateAreaID; GenaerateAreaID实际上修改了伪记录:new的area_id值。 :new最有用的一个特性----当该语句真正被执行时,:new中的存储内容就会被使用。所以系统每次都能自动生成新的号码。 <三> 表(主键、外键、CHECK、UNIQUE、DEFAULT、INDEX)<1>、SQL SERVER端语法说明 有如下SQL SERVER语句: /* ------------------------ 创建employee 表------------------------ */ IF EXISTS(SELECT 1 FROM SYSOBJECTS WHERE NAME = ‘employee’ AND TYPE = ‘U’) DROP TABLE employee GO CREATE TABLE employee ( emp_id empid /*empid为用户自定义数据类型*/ /*创建自命名主键约束*/ CONSTRAINT PK_employee PRIMARY KEY NONCLUSTERED /*创建自命名CHECK约束*/ CONSTRAINT CK_emp_id CHECK (emp_id LIKE '[A-Z][A-Z][A-Z][1-9][0-9][0-9][0-9][0-9][FM]' or emp_id LIKE '[A-Z]-[A-Z][1-9][0-9][0-9][0-9][0-9][FM]'), /* CHECK约束说明:Each employee ID consists of three characters that represent the employee's initials, followed by a five digit number ranging from 10000 to 99999 and then the employee's gender (M or F). A (hyphen) - is acceptable for the middle initial. */ fname varchar(20) NOT NULL, minit char(1) NULL, lname varchar(30) NOT NULL, ss_id varchar(9) UNIQUE, /*创建唯一性约束*/ job_id smallint NOT NULL DEFAULT 1, /*设定DEFAULT值*/ job_lvl tinyint DEFAULT 10, /*设定DEFAULT值*/ /* Entry job_lvl for new hires. */ pub_id char(4) NOT NULL DEFAULT ('9952') /*设定DEFAULT值*/ REFERENCES publishers(pub_id), /*创建系统命名外键约束*/ /* By default, the Parent Company Publisher is the company to whom each employee reports. */ hire_date datetime NOT NULL DEFAULT (getdate()), /*设定DEFAULT值*/ /* By default, the current system date will be entered. */ CONSTRAINT FK_employee_job FOREIGN KEY (job_id) REFERENCES jobs(job_id) /*创建自命名外键约束*/ ) GO
/* --------------------- 创建employee表上的index --------------------- */ IF EXISTS (SELECT 1 FROM sysindexes WHERE name = 'emp_pub_id_ind') DROP INDEX employee. emp_pub_id_ind GO CREATE INDEX emp_pub_id_ind ON employee(pub_id) GO <2>、ORACLE端语法说明 在ORACLE端的语法如下: /* ---------------------- 创建employee 表---------------------- */ DROP TABLE employee; CREATE TABLE employee ( emp_id varchar2(9) /*根据用户自定义数据类型的定义调整为varchar2(9)*/ /*创建自命名主键约束*/ CONSTRAINT PK_employee PRIMARY KEY NONCLUSTERED /*创建自命名CHECK约束*/ CONSTRAINT CK_emp_id CHECK (emp_id LIKE '[A-Z][A-Z][A-Z][1-9][0-9][0-9][0-9][0-9][FM]' or emp_id LIKE '[A-Z]-[A-Z][1-9][0-9][0-9][0-9][0-9][FM]'), /* CHECK约束说明:Each employee ID consists of three characters that represent the employee's initials, followed by a five digit number ranging from 10000 to 99999 and then the employee's gender (M or F). A (hyphen) - is acceptable for the middle initial. */ fname varchar2(20) NOT NULL, minit varchar2(1) NULL, lname varchar2(30) NOT NULL, ss_id varchar2(9) UNIQUE, /*创建唯一性约束*/ job_id number(5,0) NOT NULL /*这里考虑了SMALLINT的长度,也可调整为number*/ DEFAULT 1, /*设定DEFAULT值*/ job_lvl number(3,0) /*这里考虑了TINYINT的长度,也可调整为number*/ DEFAULT 10, /*设定DEFAULT值*/ /* Entry job_lvl for new hires. */ pub_id varchar2(4) NOT NULL DEFAULT ('9952') /*设定DEFAULT值*/ REFERENCES publishers(pub_id), /*创建系统命名外键约束*/ /* By default, the Parent Company Publisher is the company to whom each employee reports. */ hire_date date NOT NULL DEFAULT SYSDATE, /*设定DEFAULT值*/ /*这里,SQL SERVER的getdate()调整为ORACLE的SYSDATE*/ /* By default, the current system date will be entered. */ CONSTRAINT FK_employee_job FOREIGN KEY (job_id) REFERENCES jobs(job_id) /*创建自命名外键约束*/ );
/* -------------------- 创建employee表上的index -------------------- */ DROP INDEX employee. emp_pub_id_ind; CREATE INDEX emp_pub_id_ind ON employee(pub_id); <3>、从SQL SERVER向ORACLE的迁移方案 比较这两段SQL代码,可以看出,在创建表及其主键、外键、CHECK、UNIQUE、DEFAULT、INDEX时,SQL SERVER 与ORACLE的语法大致相同,但时迁移时要注意以下情况: (1) Oracle定义表字段的default属性要紧跟字段类型之后,如下: Create table MZ_Ghxx ( ghlxh number primay key , rq date default sysdate not null, …. 而不能写成 Create table MZ_Ghxx ( ghlxh number primay key , rq date not null default sysdate, …. 2)T-SQL定义表结构时,如果涉及到用默认时间和默认修改人员,全部修改如下: ZHXGRQ DATE DEFAULT SYSDATE NULL, ZHXGR CHAR(8) DEFAULT ‘FUTIAN’ NULL, 3)如表有identity定段,要先将其记录下来,建完表之后,马上建相应的序列和表触发器,并作为记录。 <四> 游标 <1>、SQL SERVER端语法说明![]() 1、DECLARE CURSOR语句![]() 语法:![]() DECLARE cursor_name [INSENSITIVE] [SCROLL] CURSOR![]() FOR select_statement![]() [FOR {READ ONLY | UPDATE [OF column_list ]}]![]() 例:![]() DECLARE authors_cursor CURSOR FOR![]() SELECT au_lname, au_fname ![]() FROM authors![]() WHERE au_lname LIKE ‘B%’![]() ORDER BY au_lname, au_fname![]() ![]() 2、OPEN语句![]() 语法:![]() OPEN cursor_name![]() 例:![]() OPEN authors_cursor![]() ![]() 3、FETCH语句![]() 语法:![]() FETCH![]() [ [ NEXT | PRIOR | FIRST | LAST | ABSOLUTE n | RELATIVE n ]![]() FROM cursor_name ![]() [INTO @variable_name1, @variable_name2,… ]![]() 例:![]() FETCH NEXT FROM authors_cursor ![]() INTO @au_lname, @au_fname![]() ![]() 4、CLOSE语句![]() 语法:![]() CLOSE cursor_name![]() 例:![]() CLOSE authors_cursor![]() ![]() 5、DEALLOCATE语句![]() 语法:![]() DEALLOCATE cursor_name![]() 例:![]() DEALLOCATE authors_cursor![]() ![]() 6、游标中的标准循环与循环终止条件判断![]() (1)FETCH NEXT FROM authors_cursor INTO @au_lname, @au_fname![]() ![]() (2)-- Check @@FETCH_STATUS to see if there are any more rows to fetch.![]() WHILE @@FETCH_STATUS = 0![]() BEGIN![]() -- Concatenate and display the current values in the variables.![]() PRINT "Author: " + @au_fname + " " + @au_lname![]() ![]() -- This is executed as long as the previous fetch succeeds.![]() FETCH NEXT FROM authors_cursor INTO @au_lname, @au_fname![]() END![]() ![]() (3)CLOSE authors_cursor![]() 7、隐式游标![]() MSSqlServer中对于数据操纵语句受影响的行数,有一个全局的变量:@@rowcount,其实它是一个隐式的游标,它记载了上条数据操纵语句所影响的行数,当@@rowcount小于1时,表时,上次没有找到相关的记录,如下:![]() Update students set lastname = ‘John’ where student_id = ‘301’![]() If @@rowcount < 1 then![]() Insert into students values (‘301’,’stdiv’,’john’,’996-03-02’)![]() 表示如果数据表中有学号为“301”的记录,则修改其名字为“John”,如果找不到相应的记录,则向数据库中插入一条“John”的记录。![]() 8、示例:![]() -- Declare the variables to store the values returned by FETCH.![]() DECLARE @au_lname varchar(40), @au_fname varchar(20)![]() ![]() DECLARE authors_cursor CURSOR FOR![]() SELECT au_lname, au_fname ![]() FROM authors![]() WHERE au_lname LIKE ‘B%’![]() ORDER BY au_lname, au_fname![]() ![]() OPEN authors_cursor![]() ![]() -- Perform the first fetch and store the values in variables.![]() -- Note: The variables are in the same order as the columns![]() -- in the SELECT statement. ![]() ![]() FETCH NEXT FROM authors_cursor INTO @au_lname, @au_fname![]() ![]() -- Check @@FETCH_STATUS to see if there are any more rows to fetch.![]() WHILE @@FETCH_STATUS = 0![]() ![]() BEGIN![]() -- Concatenate and display the current values in the variables.![]() PRINT "Author: " + @au_fname + " " + @au_lname![]() ![]() -- This is executed as long as the previous fetch succeeds.![]() FETCH NEXT FROM authors_cursor INTO @au_lname, @au_fname![]() END![]() ![]() CLOSE authors_cursor![]() ![]() DEALLOCATE authors_cursor![]() ![]() <2>、ORACLE端语法说明![]() 1、 DECLARE CURSOR语句![]() 语法:![]() CURSOR cursor_name IS select_statement;![]() 例:![]() CURSOR authors_cursor IS![]() SELECT au_lname, au_fname ![]() FROM authors![]() WHERE au_lname LIKE ‘B%’![]() ORDER BY au_lname, au_fname;![]() ![]() 2、 OPEN语句![]() 语法:![]() OPEN cursor_name![]() 例:![]() OPEN authors_cursor;![]() ![]() 3、 FETCH语句![]() 语法:![]() FETCH cursor_name INTO variable_name1 [, variable_name2,… ] ;![]() 例:![]() FETCH authors_cursor INTO au_lname, au_fname;![]() ![]() 4、 CLOSE语句![]() 语法:![]() CLOSE cursor_name![]() 例:![]() CLOSE authors_cursor;![]() ![]() 5、简单游标提取循环结构与循环终止条件判断![]() 1> 用%FOUND做循环判断条件的WHILE循环![]() (1)FETCH authors_cursor INTO au_lname, au_fname ;![]() (2)WHILE authors_cursor%FOUND LOOP![]() -- Concatenate and display the current values in the variables.![]() DBMS_OUTPUT.ENABLE;![]() DBMS_OUTPUT.PUT_LINE( ‘Author: ‘ || au_fname || ‘ ‘ || au_lname) ;![]() FETCH authors_cursor INTO au_lname, au_fname ;![]() END LOOP ;![]() (3)CLOSE authors_cursor ;![]() ![]() 2> 用%NOTFOUND做循环判断条件的简单LOOP END LOOP循环![]() (1)OPEN authors_cursor;![]() (2)LOOP![]() FETCH authors_cursor INTO au_lname, au_fname ;![]() -- Exit loop when there are no more rows to fetch.![]() EXIT WHEN authors_cursor%NOTFOUND ;![]() -- Concatenate and display the current values in the variables.![]() DBMS_OUTPUT.ENABLE;![]() DBMS_OUTPUT.PUT_LINE( ‘Author: ‘ || au_fname || ‘ ‘ || au_lname) ;![]() END LOOP ;![]() (3)CLOSE authors_cursor ;![]() 3>用游标式FOR循环,如下:![]() DECLARE![]() CURSOR c_HistoryStudents IS![]() SELECT id,first_name,last_name![]() FROM Students![]() WHERE major = ‘History’![]() BEGIN![]() FOR v_StudentData IN c_HistoryStudents LOOP![]() INSERT INTO registered_students![]() (student_id,first_name,last_name,department,course)![]() VALUES(v_StudentData.ID,v_StudentData.first_name, v_StudentData.last_name,’HIS’,301);![]() END LOOP;![]() COMMIT;![]() END;![]() 首先,记录v_StudentData没有在块的声明部分进行声明,些变量的类型是c_HistoryStudents%ROWTYPE,v_StudentData的作用域仅限于此FOR循环本身;其实,c_HistoryStudents以隐含的方式被打开和提取数据,并被循环关闭。![]() 6、隐式游标SQL%FOUND 与SQL%NOTFOUND![]() 与MSSQL SERVER 一样,ORACLE也有隐式游标,它用于处理INSERT、DELETE和单行的SELECT..INTO语句。因为SQL游标是通过PL/SQL引擎打开和关闭的,所以OPEN、FETCH和CLOSE命令是无关的。但是游标属性可以被应用于SQL游标,如下:![]() BEGIN![]() UPDATE rooms![]() SET number_seats = 100![]() WHERE room_id = 9990;![]() --如果找不相应的记录,则插入新的记录![]() IF SQL%NOTFOUND THEN![]() INSERT INTO rooms(room_id,number_seats)![]() VALUES (9990,100)![]() END IF![]() END;![]() 7、示例:![]() -- Declare the variables to store the values returned by FETCH.![]() -- Declare the CURSOR authors_cursor.![]() DECLARE ![]() au_lname varchar2(40) ;![]() au_fname varchar2(20) ;![]() CURSOR authors_cursor IS![]() SELECT au_lname, au_fname ![]() FROM authors![]() WHERE au_lname LIKE ‘B%’![]() ORDER BY au_lname, au_fname;![]() ![]() BEGIN![]() OPEN authors_cursor;![]() FETCH authors_cursor INTO au_lname, au_fname ;![]() WHILE authors_cursor%FOUND LOOP![]() -- Concatenate and display the current values in the variables.![]() DBMS_OUTPUT.ENABLE;![]() DBMS_OUTPUT.PUT_LINE( ‘Author: ‘ || au_fname || ‘ ‘ || au_lname) ;![]() FETCH authors_cursor INTO au_lname, au_fname ;![]() END LOOP ;![]() ![]() CLOSE authors_cursor ;![]() END ;![]() ![]() <3>、从SQL SERVER向ORACLE的迁移方案![]() 比较上述SQL代码,在迁移过程中要做如下调整:![]() (1)T-SQL对CURSOR的声明在主体代码中,而PL/SQL中对CURSOR的声明与变![]() 量声明同步,都要在主体代码(BEGIN关键字)之前声明,所以在迁移时要![]() 将游标声明提前,MSSQL SERVER的Cursor定义后的参数省去;![]() (2)对CUOSOR操作的语法中PL/SQL没有T-SQL里DEALLOCATE CURSOR这一部分,![]() 迁移时要将该部分语句删除。![]() (3)PL/SQL 与T-SQL对游标中的循环与循环终止条件判断的处理不太一样,根![]() 据前面的讨论并参考后面对两种语法集进行控制语句对比分析部分的叙述,![]() 建议将T-SQL中的游标提取循环调整为PL/SQL中的WHILE游标提取循环结![]() 构,这样可保持循环的基本结构大致不变,同时在进行循环终止条件判断时![]() 要注意将T-SQL中的对@@FETCH_STATUS全局变量的判断调整为对![]() CURSOR_NAME%FOUND语句进行判断。![]() (4)对于T-SQL,没有定义语句结束标志,而PL/SQL用“;”结束语句。![]() (5)对于原MSSQL SERVER类型的游标,如果游标取出的值没有参与运算的,全部采用FOR循环方式来替换;而对于取出的值还要进行其它运算的,可以采用直接在定义变量位置定义变量。![]() (6)MSSQL中对于同一游标重复定义几次的情况在ORACLE中可通过游标变量来解决.如下:![]() MSSQL SERVER 中:![]() Declare cur_ypdm cursor for![]() Select * from yp![]() Open cur_yp![]() Fetch cur_yp into @yp,@mc …![]() While @@fetch_status <> -1 ![]() Begin![]() If @@fetch_status <> -2 ![]() Begin![]() ….![]() End![]() Fetch cur_yp into @yp,@mc …![]() End![]() Close cur_ypdm![]() Deallocate cur_ypdm![]() ..![]() Declare cur_ypdm cursor for![]() Select * from yp where condition 1![]() Open cur_yp![]() Fetch cur_yp into @yp,@mc …![]() While @@fetch_status <> -1 ![]() Begin![]() If @@fetch_status <> -2 ![]() Begin![]() ….![]() End![]() Fetch cur_yp into @yp,@mc …![]() End![]() Close cur_ypdm![]() Deallocate cur_ypdm![]() ..![]() Declare cur_ypdm cursor for![]() Select * from yp where condition 2![]() Open cur_yp![]() Fetch cur_yp into @yp,@mc …![]() While @@fetch_status <> -1 ![]() Begin![]() If @@fetch_status <> -2 ![]() Begin![]() ….![]() End![]() Fetch cur_yp into @yp,@mc …![]() End![]() Close cur_ypdm![]() Deallocate cur_ypdm![]() ..![]() 在程序中,三次定义同一游标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)请注意,游标循环中中一定要退出语名,要不然执行时会出现死循环。![]() <五> 存储过程/函数![]() | |||||||||||||||||||||||||||||||||||||||||||||||||||