https://www.yiibai.com/plsql/
--/ declare v_count number(10) := 0; begin for temp_cursor in ( select a.rowid as rid,substr(a.业务工号,1,8) as emp_id from sfa2.ORDER_DETAIL a where length (业务工号) > 8 and substr(a.业务工号,1,8) = '00106430' ) loop dbms_output.put_line('test '||temp_cursor.rid); /* */ update sfa2.ORDER_DETAIL a set (a.业务姓名,a.业务职务,a.上级工号,a.上级姓名,a.EMP_POS_ID) =( select EMP_NAME,POS_NAME,DIRECTOR_EMP_ID,DIRECTOR_EMP_NAME,POS_ID from cr_report.EMP_POSITION_ORG_VIEW b where b.emp_id = temp_cursor.emp_id ) where a.rowid= temp_cursor.rid; /* ++1*/ v_count := v_count + 1 ; /* 每1000 笔 提交1次 */ if v_count >= 1000 then dbms_output.put_line('v_count'||v_count); commit; v_count := 0; end if; end loop; commit; end; /declare begin <executable command(s)> exception end;
----‘hello world’ 示例: declare message varchar2(20):= ‘hello, world!’; begin dbms_output.put_line(message); end; /
pl/sql分隔符 分隔符是一个具有特殊意义的符号。以下是在pl/sql分隔符的列表:
分隔符 描述 +, -, , / 加法,减法/否定,乘法,除法 % 属性索引 ’ 字符串分隔符 . 组件选择 (,) 表达式或列表分隔符 : 主机变量指示符 , 项目分离符 " 带引号的标识符分隔符 = 关系运算符 @ 远程访问指示符 ; 声明终止符 := 赋值运算符 => 操作符关联 || 连接运算符 ** 乘方运算符 <<, >> 标签分隔符(开始和结束) /, */ 多行注释分隔符(开始和结束) – 单行注释指示符 … 范围操作 <, >, <=, >= 关系运算符 <>, '=, ~=, ^= 不同版本的不相等的
注释 隔符 - (双连字符)和多行注释被 /* 和 / 括起来 –/ declare – variable declaration message varchar2(20):= ‘hello, world!’; begin / * pl/sql executable statement(s) */ dbms_output.put_line(message); end; /
数字数据类型及其子类型的详细信息:
数据类型 描述 pls_integer 通过2,147,483,647到-2147483648范围内有符号整数,以32位表示 binary_integer 通过2,147,483,647到-2147483648范围内的有符号整数,以32位表示 binary_float 单精度ieee 754格式的浮点数 binary_double 双精度ieee 754格式的浮点数 number(prec, scale) 定点或浮点数在范围1e-130至(但不包括)绝对值1.0e126。 number变量也可以表示0 dec(prec, scale) ansi具体的定点类型使用38位小数最大精度 decimal(prec, scale) ibm特定的固定点型具有38位小数最大精度 numeric(pre, secale) 浮点类型具有38位小数最大精度。 double precision 具有126个二进制数字最大精度ansi特定浮点型(约38位十进制数) float 具有126个二进制数字(约38位十进制数)最大精度ansi和ibm特定的浮点型 int 具有38位小数最大精度ansi具体的整数类型 integer ansi和ibm的38位小数最大精度具体的整数类型 smallint ansi和ibm的38位小数最大精度具体的整数类型 real 具有63位二进制数字最大精度浮点型(大约18位小数)
字符数据类型及其子类型的详细信息:
数据类型 描述 char 具有32,767个字节的最大尺寸固定长度字符串 varchar2 具有32,767个字节的最大尺寸变长字符串 raw 可变长度的二进制或字节字符串的32,767个字节的最大尺寸,而不是由pl/ sql解释 nchar 具有32,767个字节的最大尺寸的固定长度国家字符串 nvarchar2 具有32,767个字节的最大尺寸可变长度国家字符串 long 具有32,760字节最大尺寸变长字符串 long raw 可变长度的二进制或字节字符串的32,760字节的最大尺寸,而不是由pl/sql解释 rowid 物理行标识符,一行在一个普通的表中的地址 urowid 物理通用行标识符(物理,逻辑,或外国的行标识符)
字段名称 有效日期时间值 有效的间隔值 year -4712 to 9999 (年除外 0) 任何非零整数 month 01 to 12 0 to 11 day 01 to 31 (受制于年份和月份的数值,按日历的区域设置的规则) 任何非零整数 hour 00 to 23 0 to 23 minute 00 to 59 0 to 59 second 00 to 59.9(n), 其中,9(n)是时间小数秒精度 0 to 59.9(n), 其中,9(n)是区间小数秒精度 timezone_hour -12 to 14 (范围可容纳夏令时更改) 不适用 timezone_minute 00 to 59 不适用 timezone_region 在动态性能视图找到v t i m e z o n e n a m e s 不 适 用 t i m e z o n e a b b r 在 动 态 性 能 视 图 找 到 v timezone_names 不适用 timezone_abbr 在动态性能视图找到v timezonenames不适用timezoneabbr在动态性能视图找到vtimezone_names 不适用
可以定义和使用自己的子类型。
declare subtype name is char(20); subtype message is varchar2(100); salutation name; greetings message; begin salutation := 'reader '; greetings := ‘welcome to the world of pl/sql’; dbms_output.put_line('hello ’ || salutation || greetings); end; /
声明一个变量的语法是:
variable_name [constant] datatype [not null] [:= | default initial_value]
sales number(10, 2); pi constant double precision := 3.1415; name varchar2(25); address varchar2(100);
使用 default 关键字 使用 assignment 操作符
counter binary_integer := 0; greetings varchar2(20) default ‘have a good day’;
declare c_id customers.id%type := 1; c_name customers.name%type; c_addr customers.address%type; c_sal customers.salary%type; begin select name, address, salary into c_name, c_addr, c_sal from customers where id = c_id;
dbms_output.put_line ('customer ’ ||c_name || ’ from ’ || c_addr || ’ earns ’ || c_sal); end; /
声明一个常量 常量使用constant关键字声明。它需要一个初始值,并且不允许被改变该值。例如: pi constant number := 3.141592654;
declare – constant declaration pi constant number := 3.141592654; – other declarations radius number(5,2); dia number(5,2); circumference number(7, 2); area number (10, 2); begin – processing radius := 9.5; dia := radius * 2; circumference := 2.0 * pi * radius; area := pi * radius * radius; – output dbms_output.put_line('radius: ’ || radius); dbms_output.put_line('diameter: ’ || dia); dbms_output.put_line('circumference: ’ || circumference); dbms_output.put_line('area: ’ || area); end; /
当上述代码在sql提示符执行时,它产生了以下结果:
radius: 9.5 diameter: 19 circumference: 59.69 area: 283.53
pl/sql procedure successfully completed.
declare message varchar2(30):= ‘‘that’‘s yiibai.com!’’; begin dbms_output.put_line(message); end; /
算术运算符 关系运算符 比较运算符 逻辑运算符 字符串运算符
算术运算符 描述 示例
相加两个操作数 a + b = 15 第一个操作数减去第二个操作数 a - b = 5 两个操作数相乘 a * b = 50/ 两个操作数相除 a / b = 2 ** 乘方运算 a ** b = 100000
关系运算符 描述 示例 = 检查两个操作数的值是否相等,如果是的话那么条件为真。 (a = b) 结果为 false. != ,<> ,~= 检查两个操作数的值是否相等,如果值不相等,则条件变为真。 (a != b) 结果为 true.
检查左边的操作数的值是否大于右操作数的值,如果是的话那么条件为真。 (a > b) 结果为 false. < 检查左边的操作数的值是否小于右操作数的值,如果是的话那么条件为真。 (a < b) 结果为 true. = 检查左边的操作数的值是否大于或等于右操作数的值,如果是的话那么条件为真。 (a >= b) 结果为 false. <= 检查左边的操作数的值是否小于或等于右操作数的值,如果是的话那么条件为真。 (a <= b) 结果为 true.
比较运算符 描述 示例 like like操作一个字符,字符串或clob值进行比较匹配模式则返回true,如果不匹配模式则false 如果 ‘zara ali’ like ‘z% a_i’ 返回一个布尔值true, 然而, ‘nuha ali’ like ‘z% a_i’ 返回布尔值 false between between 运算符测试一个值是否位于规定的范围内. x between a and b 意思就是 x >= a and x <= b. 如果 x = 10 那么 x between 5 and 20 返回 true, x between 5 and 10 返回 true, 但是 x between 11 and 20 返回 false in in运算符的测试设置成员. x in (set) 意味着x等于集合中的某一个成员 如果 x = ‘m’ then, x in (‘a’, ‘b’, ‘c’) 返回布尔值false,但x在(‘m’, ‘n’, ‘o’) 返回布尔值 true. is null is null运算符返回布尔值true,如果它的操作数是null或false(如果它不为null)。包括null值的比较总能取得null 如果 x = ‘m’, 那么 ‘x is null’ 返回布尔值false
逻辑运算符 描述 示例 and 称为逻辑and运算。 如果两个操作数为true,则条件为true (a and b) 结果为 false. or 所谓的逻辑或操作。如果任何两个操作数为true,则条件变为true (a or b) 结果为 true. not 所谓逻辑非运算符。用于反向操作数的逻辑状态。如果条件为true,那么逻辑非运算符将使它为false not (a and b) 结果为 true.
具有最高优先级的操作出现在表的顶部,那些具有最低出现在底部。在表达式,更高的优先级运算符将首先计算。
运算符 操作符 ** 指数运算 +, - 加法,取反 *, / 乘法,除法 +, -, || 加,减,并置 ‘= <, >, <=, >=, <>, !=, ~=, ^=, is null, like, between, in 比较 not 逻辑否定 and 关联 or 包含
like 运算符:
declare procedure compare (value varchar2, pattern varchar2 ) is begin if value like pattern then dbms_output.put_line (‘true’); else dbms_output.put_line (‘false’); end if; end;
begin compare(‘zara ali’, ‘z%a_i’); compare(‘nuha ali’, ‘z%a_i’); end; / 当上述代码在sql提示符执行时,它产生了以下结果:
true false
between运算符:
declare x number(2) := 10; begin if (x between 5 and 20) then dbms_output.put_line(‘true’); else dbms_output.put_line(‘false’); end if;
if (x between 5 and 10) then dbms_output.put_line(‘true’); else dbms_output.put_line(‘false’); end if;
if (x between 11 and 20) then dbms_output.put_line(‘true’); else dbms_output.put_line(‘false’); end if; end; /
in和is null运算符:
declare letter varchar2(1) := ‘m’; begin if (letter in (‘a’, ‘b’, ‘c’)) then dbms_output.put_line(‘true’); else dbms_output.put_line(‘false’); end if;
if (letter in (‘m’, ‘n’, ‘o’)) then dbms_output.put_line(‘true’); else dbms_output.put_line(‘false’); end if;
if (letter is null) then dbms_output.put_line(‘true’); else dbms_output.put_line(‘false’); end if; end; /
false true false
----if elseif else end-------------
declare a number(2) := 10; begin a:= 10; – check the boolean condition using if statement if( a < 20 ) then – if condition is true then print the following dbms_output.put_line('a is less than 20 ’ ); end if; dbms_output.put_line('value of a is : ’ || a); end; /
declare c_id customers.id%type := 1; c_sal customers.salary%type; begin select salary into c_sal from customers where id = c_id; if (c_sal <= 2000) then update customers set salary = salary + 1000 where id = c_id; dbms_output.put_line (‘salary updated’); end if; end; /
declare a number(3) := 100; begin if ( a = 10 ) then dbms_output.put_line(‘value of a is 10’ ); elsif ( a = 20 ) then dbms_output.put_line(‘value of a is 20’ ); elsif ( a = 30 ) then dbms_output.put_line(‘value of a is 30’ ); else dbms_output.put_line(‘none of the values is matching’); end if; dbms_output.put_line('exact value of a is: '|| a ); end; /
declare grade char(1) := ‘a’; begin case grade when ‘a’ then dbms_output.put_line(‘excellent’); when ‘b’ then dbms_output.put_line(‘very good’); when ‘c’ then dbms_output.put_line(‘well done’); when ‘d’ then dbms_output.put_line(‘you passed’); when ‘f’ then dbms_output.put_line(‘better try again’); else dbms_output.put_line(‘no such grade’); end case; end; /
declare grade char(1) := ‘b’; begin case when grade = ‘a’ then dbms_output.put_line(‘excellent’); when grade = ‘b’ then dbms_output.put_line(‘very good’); when grade = ‘c’ then dbms_output.put_line(‘well done’); when grade = ‘d’ then dbms_output.put_line(‘you passed’); when grade = ‘f’ then dbms_output.put_line(‘better try again’); else dbms_output.put_line(‘no such grade’); end case; end; /
declare a number(3) := 100; b number(3) := 200; begin – check the boolean condition if( a = 100 ) then – if condition is true then check the following if( b = 200 ) then – if condition is true then print the following dbms_output.put_line(‘value of a is 100 and b is 200’ ); end if; end if; dbms_output.put_line('exact value of a is : ’ || a ); dbms_output.put_line('exact value of b is : ’ || b ); end; /
—循环语句—
declare x number := 10; begin loop dbms_output.put_line(x); x := x + 10; if x > 50 then exit; end if; end loop; – after exit, control resumes here dbms_output.put_line('after exit x is: ’ || x); end; /
declare x number := 10; begin loop dbms_output.put_line(x); x := x + 10; exit when x > 50; end loop; – after exit, control resumes here dbms_output.put_line('after exit x is: ’ || x); end; /
declare a number(2) := 10; begin while a < 20 loop dbms_output.put_line('value of a: ’ || a); a := a + 1; end loop; end; /
for counter in initial_value … final_value loop sequence_of_statements; end loop;
declare a number(2); begin for a in 10 … 20 loop dbms_output.put_line('value of a: ’ || a); end loop; end; /
declare a number(2) ; begin for a in reverse 10 … 20 loop dbms_output.put_line('value of a: ’ || a); end loop; end; / 当上述代码在sql提示符执行时,它产生了以下结果:
value of a: 20 value of a: 19 value of a: 18 value of a: 17 value of a: 16 value of a: 15 value of a: 14 value of a: 13 value of a: 12 value of a: 11 value of a: 10
loop sequence of statements1 loop sequence of statements2 end loop; end loop;
for counter1 in initial_value1 … final_value1 loop sequence_of_statements1 for counter2 in initial_value2 … final_value2 loop sequence_of_statements2 end loop; end loop;
while condition1 loop sequence_of_statements1 while condition2 loop sequence_of_statements2 end loop; end loop;
declare i number(3); j number(3); begin i := 2; loop j:= 2; loop exit when ((mod(i, j) = 0) or (j = i)); j := j +1; end loop; if (j = i ) then dbms_output.put_line(i || ’ is prime’); end if; i := i + 1; exit when i = 50; end loop; end; /
declare a number(2) := 10; begin – while loop execution while a < 20 loop dbms_output.put_line ('value of a: ’ || a); a := a + 1; if a > 15 then – terminate the loop using the exit statement exit; end if; end loop; end; /
declare a number(2) := 10; begin – while loop execution while a < 20 loop dbms_output.put_line ('value of a: ’ || a); a := a + 1; – terminate the loop using the exit when statement exit when a > 15; end loop; end; /
declare a number(2) := 10; begin – while loop execution while a < 20 loop dbms_output.put_line ('value of a: ’ || a); a := a + 1; if a = 15 then – skip the loop using the continue statement a := a + 1; continue; end if; end loop; end; /
value of a: 10 value of a: 11 value of a: 12 value of a: 13 value of a: 14 value of a: 16 value of a: 17 value of a: 18 value of a: 19
declare a number(2) := 10; begin <> – while loop execution while a < 20 loop dbms_output.put_line ('value of a: ’ || a); a := a + 1; if a = 15 then a := a + 1; goto loopstart; end if; end loop; end; /
value of a: 10 value of a: 11 value of a: 12 value of a: 13 value of a: 14 value of a: 16 value of a: 17 value of a: 18 value of a: 19
declare name varchar2(20); company varchar2(30); introduction clob; choice char(1); begin name := ‘john smith’; company := ‘infotech’; introduction := ’ hello! i’‘m john smith from infotech.’; choice := ‘y’; if choice = ‘y’ then dbms_output.put_line(name); dbms_output.put_line(company); dbms_output.put_line(introduction); end if; end; / 当上述代码在sql提示符执行时,它产生了以下结果:
john smith infotech corporation hello! i’m john smith from infotech.
s.n. 函数及用途 1 ascii(x); 返回字符 x 的 ascii 值 2 chr(x); 返回字符 x 的 ascii 值 3 concat(x, y); 连接字符串x和y,并返回附加的字符串 4 initcap(x); 每个单词的首字母x中转换为大写,并返回该字符串 5 instr(x, find_string [, start] [, occurrence]); 搜索find_string在x中并返回它出现的位置 6 instrb(x); 返回另一个字符串中字符串的位置,但返回以字节为单位的值 7 length(x); 返回x中的字符数 8 lengthb(x); 返回为单字节字符集的字节的字符串的长度 9 lower(x); 在x转换为小写字母,并返回该字符串 10 lpad(x, width [, pad_string]) ; x用空格向左填充,把字符串的总长度达宽字符 11 ltrim(x [, trim_string]); 从x的左修剪字符 12 nanvl(x, value); 如果x匹配nan的特殊值(非数字)则返回其值,否则返回x 13 nls_initcap(x); 相同initcap函数,但它可以使用不同的排序方法所指定nlssort 14 nls_lower(x) ; 同样的,不同的是它可以使用不同的排序方法所指定nlssort lower函数 15 nls_upper(x); 相同,不同之处在于它可以使用不同的排序方法所指定nlssort upper函数 16 nlssort(x); 改变排序的字符的方法。任何nls函数之前必须指定该参数; 否则,默认的排序被使用 17 nvl(x, value); 返回如果x为null返回null; 否则返回x 18 nvl2(x, value1, value2); 如果x不为null返回value1; 如果x为null,则返回value2 19 replace(x, search_string, replace_string); 搜索x对于search_string并替换使用replace_string它 20 rpad(x, width [, pad_string]); 填充x到右侧 21 rtrim(x [, trim_string]); 从x右边修剪 22 soundex(x) ; 返回包含x的拼音表示形式的字符串 23 substr(x, start [, length]); 返回x的一个子开始于由start指定的位置。可选长度为子字符串 24 substrb(x); 相同substr除外的参数均以字节代替字符的单字节字符的系统 25 trim([trim_char from) x); 从左侧和右侧修剪x字符 26 upper(x); x转换为大写字母,并返回该字符串
declare greetings varchar2(11) := ‘hello world’; begin dbms_output.put_line(upper(greetings));
dbms_output.put_line(lower(greetings));
dbms_output.put_line(initcap(greetings));
/* retrieve the first character in the string */ dbms_output.put_line ( substr (greetings, 1, 1));
/* retrieve the last character in the string */ dbms_output.put_line ( substr (greetings, -1, 1));
/* retrieve five characters, starting from the seventh position. */ dbms_output.put_line ( substr (greetings, 7, 5));
/* retrieve the remainder of the string, starting from the second position. */ dbms_output.put_line ( substr (greetings, 2));
/* find the location of the first “e” */ dbms_output.put_line ( instr (greetings, ‘e’)); end; /
当上述代码在sql提示符执行时,它产生了以下结果:
hello world hello world hello world h d world ello world 2
-----数组----- create or replace type varray_type_name is varray(n) of <element_type>
varray_type_name 就是一个有效的属性名 n是varray元素(最大值)的数目 element_type 就是所述数组的元素的数据类型。 varray的最大长度可以使用alter type语句来改变。
例如, create or replace type namearray as varray(3) of varchar2(10);
type namearray is varray(5) of varchar2(10); type grades is varray(5) of integer;
declare type namesarray is varray(5) of varchar2(10); type grades is varray(5) of integer; names namesarray; marks grades; total integer; begin names := namesarray(‘kavita’, ‘pritam’, ‘ayan’, ‘rishav’, ‘aziz’); marks:= grades(98, 97, 78, 87, 92); total := names.count; dbms_output.put_line('total ‘|| total || ’ students’); for i in 1 … total loop dbms_output.put_line('student: ’ || names(i) || ’ marks: ’ || marks(i)); end loop; end; /
declare cursor c_customers is select name from customers; type c_list is varray (6) of customers.name%type; name_list c_list := c_list(); counter integer :=0; begin for n in c_customers loop counter := counter + 1; name_list.extend; name_list(counter) := n.name; dbms_output.put_line(‘customer(’||counter ||’):’||name_list(counter)); end loop; end; /
----创建过程---- 过程使用create or replace procedure语句创建,使用create or replace procedure语句简化语法如下:
create [or replace] procedure procedure_name [(parameter_name [in | out | in out] type [, …])] {is | as} begin < procedure_body > end procedure_name; 这里,
procedure-name 指定的程序的名称 [or replace] 选项允许修改现有的程序 可选的参数列表中包含的名称,模式和类型的参数。in表示该值将被从外部传递,out表示该参数将被用于从过程返回一个值到外面 procedure-body 包含可执行部分 as关键字来代替了is关键字用于创建一个独立的程序。
例子: 下面的示例创建一个字符串的简单过程执行时将’hello world!“显示在屏幕上。
create or replace procedure greetings as begin dbms_output.put_line(‘hello world!’); end; /
使用execute关键字
从pl/sql块调用过程的名称
名为“greetings”的上述程序可以调用execute关键字为:
execute greetings; 上述调用会显示: hello world
pl/sql procedure successfully completed.
begin greetings; end; /
删除独立程序 一个独立的程序使用drop procedure语句删除。删除一个程序的语法是:
drop procedure procedure-name; begin drop procedure greetings; end; /
declare a number; b number; c number;
procedure findmin(x in number, y in number, z out number) is begin if x < y then z:= x; else z:= y; end if; end;
begin a:= 23; b:= 45; findmin(a, b, c); dbms_output.put_line(’ minimum of (23, 45) : ’ || c); end; /
declare a number; procedure squarenum(x in out number) is begin x := x * x; end; begin a:= 23; squarenum(a); dbms_output.put_line(’ square of (23): ’ || a); end; /
----创建函数----- 建立一个独立函数可以使用create function语句创建。create or replace procedure语句简化语法如下:
create [or replace] function function_name [(parameter_name [in | out | in out] type [, …])] return return_datatype {is | as} begin < function_body > end [function_name]; 这里,
function-name 指定函数的名称 [or replace] 选项允许修改现有的函数 可选的参数列表中包含的名称,模式和类型的参数。in表示该值将被从外部传递和out表示该参数将被用于过程外面返回一个值 函数必须包含一个return语句 return 子句指定要在函数返回的数据类型 function-body 包含可执行部分 as关键字来代替了is关键字用于创建一个独立的函数
示例: 下面的示例说明创建和调用一个独立的函数。函数返回在customers表中的客户总数。我们将使用customers表,已在前面pl/sql变量的章节中创建:
select * from customers;
±—±---------±----±----------±---------+ | id | name | age | address | salary | ±—±---------±----±----------±---------+ | 1 | ramesh | 32 | ahmedabad | 2000.00 | | 2 | khilan | 25 | delhi | 1500.00 | | 3 | kaushik | 23 | kota | 2000.00 | | 4 | chaitali | 25 | mumbai | 6500.00 | | 5 | hardik | 27 | bhopal | 8500.00 | | 6 | komal | 22 | mp | 4500.00 | ±—±---------±----±----------±---------+ create or replace function totalcustomers return number is total number(2) := 0; begin select count(*) into total from customers;
return total; end; /
declare c number(2); begin c := totalcustomers(); dbms_output.put_line('total no. of customers: ’ || c); end; /
declare a number; b number; c number; function findmax(x in number, y in number) return number is z number; begin if x > y then z:= x; else z:= y; end if;
return z; end; begin a:= 23; b:= 45;
c := findmax(a, b); dbms_output.put_line(’ maximum of (23,45): ’ || c); end; /
maximum of (23,45): 45
递归函数 declare num number; factorial number;
function fact(x number) return number is f number; begin if x=0 then f := 1; else f := x * fact(x-1); end if; return f; end;
begin num:= 6; factorial := fact(num); dbms_output.put_line(’ factorial '|| num || ’ is ’ || factorial); end; /
factorial 6 is 720
属性 描述 %found 返回true如果一个insert,update或delete语句影响了一行或多行或select into语句返回一行或多行。否则,它将返回false。 %notfound 逻辑相反%found。返回true如果一个insert,update或delete语句影响没有行或select into语句返回任何行。否则,它将返回false。 %isopen 隐式游标总是返回false,因为oracle执行其相关的sql语句之后自动关闭sql游标。 %rowcount 返回受insert,update影响的行数,或delete语句,或者通过一个select into语句返回。
declare total_rows number(2); begin update customers set salary = salary + 500; if sql%notfound then dbms_output.put_line(‘no customers selected’); elsif sql%found then total_rows := sql%rowcount; dbms_output.put_line( total_rows || ’ customers selected '); end if; end; /
6 customers selected
----显式游标---- cursor cursor_name is select_statement; 使用显式游标的工作包括四个步骤:
声明游标用于初始化在存储器 打开游标分配内存 获取游标检索数据 关闭游标释放分配的内存
declare c_id customers.id%type; c_name customers.name%type; c_addr customers.address%type; cursor c_customers is select id, name, address from customers; begin open c_customers; loop fetch c_customers into c_id, c_name, c_addr; exit when c_customers%notfound; dbms_output.put_line(c_id || ’ ’ || c_name || ’ ’ || c_addr); end loop; close c_customers; end; / 当上述代码在sql提示符执行时,它产生了以下结果:
1 ramesh ahmedabad 2 khilan delhi 3 kaushik kota 4 chaitali mumbai 5 hardik bhopal 6 komal mp
-----记录----------- 记录的以下几种类型: 基于数据表 基于游标的记录 用户自定义记录
基于表的记录 在%rowtype属性使程序员创建 基于表格和基于游标记录。
说明基于表的记录的概念。使用我们已经创建,并在前面的章节中使用的customers表:
declare customer_rec customers%rowtype; begin select * into customer_rec from customers where id = 5;
dbms_output.put_line('customer id: ’ || customer_rec.id); dbms_output.put_line('customer name: ’ || customer_rec.name); dbms_output.put_line('customer address: ’ || customer_rec.address); dbms_output.put_line('customer salary: ’ || customer_rec.salary); end; /
customer id: 5 customer name: hardik customer address: bhopal customer salary: 9000
基于游标记录 将说明了基于游标记录的概念。使用我们已经创建,并在前面的章节中使用的customers表:
declare cursor customer_cur is select id, name, address from customers; customer_rec customer_cur%rowtype; begin open customer_cur; loop fetch customer_cur into customer_rec; exit when customer_cur%notfound; dbms_output.put_line(customer_rec.id || ’ ’ || customer_rec.name); end loop; end; /
1 ramesh 2 khilan 3 kaushik 4 chaitali 5 hardik 6 komal
用户自定义记录 pl/sql提供了一个用户定义的记录类型,允许定义不同的记录结构。 记录由不同的字段组成。 假设要跟踪图书馆的书籍。 可能要跟踪有关每本书以下属性: 标题 作者 科目 书籍id
定义一条记录 记录类型定义为: type type_name is record ( field_name1 datatype1 [not null] [:= default expression], field_name2 datatype2 [not null] [:= default expression], … field_namen datatypen [not null] [:= default expression); record-name type_name; 这里是声明图书的记录方式:
declare type books is record (title varchar(50), author varchar(50), subject varchar(100), book_id number); book1 books; book2 books; 访问字段 要访问记录的字段,我们使用点(.)运算符。成员访问运算符编码为记录变量名和访问字段期间。
declare type books is record (title varchar(50), author varchar(50), subject varchar(100), book_id number); book1 books; book2 books; begin – book 1 specification book1.title := ‘c programming’; book1.author := 'nuha ali '; book1.subject := ‘c programming tutorial’; book1.book_id := 6495407;
– book 2 specification book2.title := ‘telecom billing’; book2.author := ‘zara ali’; book2.subject := ‘telecom billing tutorial’; book2.book_id := 6495700;
– print book 1 record dbms_output.put_line('book 1 title : '|| book1.title); dbms_output.put_line('book 1 author : '|| book1.author); dbms_output.put_line('book 1 subject : '|| book1.subject); dbms_output.put_line('book 1 book_id : ’ || book1.book_id);
– print book 2 record dbms_output.put_line('book 2 title : '|| book2.title); dbms_output.put_line('book 2 author : '|| book2.author); dbms_output.put_line('book 2 subject : '|| book2.subject); dbms_output.put_line('book 2 book_id : '|| book2.book_id); end; /
book 1 title : c programming book 1 author : nuha ali book 1 subject : c programming tutorial book 1 book_id : 6495407 book 2 title : telecom billing book 2 author : zara ali book 2 subject : telecom billing tutorial book 2 book_id : 6495700
记录作为子程序参数 可以通过记录作为子程序参数,非常相似传递任何其他变量的方式。访问可以象在上面的例子 - 已访问类似的方式记录字段:
declare type books is record (title varchar(50), author varchar(50), subject varchar(100), book_id number); book1 books; book2 books;
procedure printbook (book books) is begin dbms_output.put_line ('book title : ’ || book.title); dbms_output.put_line('book author : ’ || book.author); dbms_output.put_line( 'book subject : ’ || book.subject); dbms_output.put_line( 'book book_id : ’ || book.book_id); end;
begin – book 1 specification book1.title := ‘c programming’; book1.author := 'nuha ali '; book1.subject := ‘c programming tutorial’; book1.book_id := 6495407;
– book 2 specification book2.title := ‘telecom billing’; book2.author := ‘zara ali’; book2.subject := ‘telecom billing tutorial’; book2.book_id := 6495700;
– use procedure to print book info printbook(book1); printbook(book2); end; /
----------异常--------------- 两种类型的异常: 系统定义的异常 用户定义的异常
declare begin <executable command(s)> exception when exception1 then exception1-handling-statements when exception2 then exception2-handling-statements when exception3 then exception3-handling-statements … when others then exception3-handling-statements end;
declare c_id customers.id%type := 8; c_name customers.name%type; c_addr customers.address%type; begin select name, address into c_name, c_addr from customers where id = c_id;
dbms_output.put_line ('name: '|| c_name); dbms_output.put_line ('address: ’ || c_addr); exception when no_data_found then dbms_output.put_line(‘no such customer!’); when others then dbms_output.put_line(‘error!’); end; /
no such customer!
引发异常 异常是数据库服务器自动在内部数据库错误,但异常可以明确地提出由程序员使用命令raise。以下是引发异常的简单的语法:
declare exception_name exception; begin if condition then raise exception_name; end if; exception when exception_name then statement; end; 可以在引发oracle的标准异常或任何用户定义的异常使用上述语法。 下一节会显示如何引发用户定义异常,引发oracle标准异常以及类似的方法的例子。
用户自定义异常 pl/sql允许根据程序的需要定义自己的异常。用户定义的异常必须声明, 然后明确地提出使用一个raise语句或程序dbms_standard.raise_application_error。
声明一个异常的语法是:
declare my-exception exception; 示例: 下面的例子说明了这个概念。该程序需要一个客户id,当用户输入了一个无效的id,异常invalid_id引发。
declare c_id customers.id%type := &cc_id; c_name customers.name%type; c_addr customers.address%type;
– user defined exception ex_invalid_id exception; begin if c_id <= 0 then raise ex_invalid_id; else select name, address into c_name, c_addr from customers where id = c_id;
dbms_output.put_line ('name: '|| c_name); dbms_output.put_line ('address: ' || c_addr);end if; exception when ex_invalid_id then dbms_output.put_line(‘id must be greater than zero!’); when no_data_found then dbms_output.put_line(‘no such customer!’); when others then dbms_output.put_line(‘error!’); end; / 当上述代码在sql提示符执行时,它产生了以下结果:
enter value for cc_id: -6 (let’s enter a value -6) old 2: c_id customers.id%type := &cc_id; new 2: c_id customers.id%type := -6; id must be greater than zero!
– select * from customer –/ declare c_id customer.id%type :=‘0011001472’; ----‘0011001472’ ; – &cc_id; c_name customer.name%type; c_addr customer.short_name%type; – user defined exception ex_invalid_id exception; begin if c_id <= 0 then raise ex_invalid_id; else select name, short_name into c_name, c_addr from customer where id = c_id;
dbms_output.put_line ('name: '|| c_name); dbms_output.put_line ('address: ' || c_addr);end if; exception when ex_invalid_id then dbms_output.put_line(‘id must be greater than zero!’); when no_data_found then dbms_output.put_line(‘no such customer!’); when others then dbms_output.put_line(‘error!’); end; /
触发器是存储程序,它会自动执行或发射当一些事件发生。触发器,事实上,写入响应于以下任一事件将被执行: 数据库操作(dml)语句(delete,insert,update或) 数据库定义(ddl)语句(create,alter或drop) 数据库操作(servererror,登录,注销,启动或关机)
触发器可以在表,视图,模式或数据库与该事件相关联上定义
触发器的优点 触发器可以用于以下目的写:
自动生成一些派生列值 实施参照完整性 事件日志和对表的访问存储信息 审计 表的同步复制 实行安全许可 防止非法交易 创建触发器
创建触发器的语法:
create [or replace ] trigger trigger_name {before | after | instead of } {insert [or] | update [or] | delete} [of col_name] on table_name [referencing old as o new as n] [for each row] when (condition) declare declaration-statements begin executable-statements exception exception-handling-statements end; 那么,
create [or replace] trigger trigger_name: 创建或替换现有的触发器:trigger_name {before | after | instead of} : 指定当触发将被执行。在instead of子句用于在视图中创建触发器 {insert [or] | update [or] | delete}: 指定dml操作 [of col_name]: 指定将被更新的列名 [on table_name]: 指定触发器相关联的表的名称 [referencing old as o new as n]: 可以参考新旧值的各种dml语句,如insert,update和delete [for each row]: 指定的行级触发器,即触发器将每一行受到影响执行。否则,当执行sql语句,这被称为表级触发器触发将执行一次 when (condition): 触发器将触发的条件。此子句仅适用于行级触发器有效
首先,将使用我们已经创建,并在前面的章节中使用的customers表:
select * from customers;
±—±---------±----±----------±---------+ | id | name | age | address | salary | ±—±---------±----±----------±---------+ | 1 | ramesh | 32 | ahmedabad | 2000.00 | | 2 | khilan | 25 | delhi | 1500.00 | | 3 | kaushik | 23 | kota | 2000.00 | | 4 | chaitali | 25 | mumbai | 6500.00 | | 5 | hardik | 27 | bhopal | 8500.00 | | 6 | komal | 22 | mp | 4500.00 | ±—±---------±----±----------±---------+ 下面的程序创建了customers表中,将触发insert或update或delete在customers表进行操作的行级触发。 触发器将显示工资的旧值和新值之间的差额:
create or replace trigger display_salary_changes before delete or insert or update on customers for each row when (new.id > 0) declare sal_diff number; begin sal_diff := :new.salary - :old.salary; dbms_output.put_line('old salary: ’ || :old.salary); dbms_output.put_line('new salary: ’ || :new.salary); dbms_output.put_line('salary difference: ’ || sal_diff); end; / 当上述代码在sql提示符执行时,它产生了以下结果:
trigger created. 这里以下两点是重要的,应小心注意:
old和new引用是不可用于表级触发器,而不可以使用它们的创纪录级别的触发器。
如果想查询表中相同的触发,那么应用应该使用after关键字,因为触发器可以查询该表, 或再次改变它最初的变化仅适用后的表是回到一致的状态。
上述触发已经写在这样一种方式,它会在任何delete、insert或update操作在表上之前执行, 但可以夺触发器上编写一个或多个操作,例如before delete,这将会触发每当一个记录将使用在表上删除操作被删除。 触发一个触发器 让我们在customers表执行某些dml操作。这里有一个insert语句,这将在表中创建一个新的记录:
insert into customers (id,name,age,address,salary) values (7, ‘kriti’, 22, ‘hp’, 7500.00 ); 当记录在customers表中创建,上面创建触发器display_salary_changes将被触发,它会显示以下结果: old salary: new salary: 7500 salary difference: 因为这是一个新的记录,因此基本工资不可用及以上的结果来为空(null)。现在,让我们对customers表进行多一个dml操作。这里有一个update语句,该语句将更新表中现有的记录:
update customers set salary = salary + 500 where id = 2; 当记录在customers表更新,上面创建触发器display_salary_changes将被触发,它会显示以下结果:
old salary: 1500 new salary: 2000 salary difference: 500
包有两个强制性的部分:
包装规范定义包体或定义包装规范定义 规范是接口到包。 它只是声明的类型,变量,常量,异常,游标和子程序可从封装外部引用。 换句话说,它包含关于包的内容的所有信息,但不包括用于子程序的代码。
置于规范的所有对象被称为公共对象。任何子程序在封装主体中没有包定义但编码被称为私有对象。
下面的代码片段显示了具有单一的程序包规范定义。一个包中可以定义的全局变量和多个程序或函数。
create package cust_sal as procedure find_sal(c_id customers.id%type); end cust_sal; / 当上述代码在sql提示符执行时,它产生了以下结果:
package created.
包主体 包体已经在包定义和其他私人声明中声明的各种方法,这是从代码隐藏在包外的代码。
create package body语句用于创建包体。下面的代码片段显示了包体声明上面创建的cust_sal包。在前面学习中,我们已经在数据库中创建了一个customers表 - pl/sql变量 这一章节。
create or replace package body cust_sal as procedure find_sal(c_id customers.id%type) is c_sal customers.salary%type; begin select salary into c_sal from customers where id = c_id; dbms_output.put_line('salary: '|| c_sal); end find_sal; end cust_sal; / 当上述代码在sql提示符执行时,它产生了以下结果:
package body created. 使用包元素 访问包元素(变量,过程或函数)的语法如下:
package_name.element_name;
想想,我们已经在上面的数据库模式中创建的包,下面的程序是使用cust_sal包的find_sal方法:
declare code customers.id%type := &cc_id; begin cust_sal.find_sal(code); end; / 当上面的代码在sql提示符下执行,它提示输入客户id,当输入一个id,它会显示相应的薪酬如下:
enter value for cc_id: 1 salary: 3000
例子: 下面的程序提供了一个更为完整的方案。我们将使用存储在数据库中的customers表的以下记录:
select * from customers;
±—±---------±----±----------±---------+ | id | name | age | address | salary | ±—±---------±----±----------±---------+ | 1 | ramesh | 32 | ahmedabad | 3000.00 | | 2 | khilan | 25 | delhi | 3000.00 | | 3 | kaushik | 23 | kota | 3000.00 | | 4 | chaitali | 25 | mumbai | 7500.00 | | 5 | hardik | 27 | bhopal | 9500.00 | | 6 | komal | 22 | mp | 5500.00 | ±—±---------±----±----------±---------+ 包规范定义: create or replace package c_package as – adds a customer procedure addcustomer(c_id customers.id%type, c_name customers.name%type, c_age customers.age%type, c_addr customers.address%type, c_sal customers.salary%type);
– removes a customer procedure delcustomer(c_id customers.id%type); –lists all customers procedure listcustomer;
end c_package; / 当上面的代码在sql提示符下执行,它会创建上述包,并显示以下结果:
创建包的主体部分: create or replace package body c_package as procedure addcustomer(c_id customers.id%type, c_name customers.name%type, c_age customers.age%type, c_addr customers.address%type, c_sal customers.salary%type) is begin insert into customers (id,name,age,address,salary) values(c_id, c_name, c_age, c_addr, c_sal); end addcustomer;
procedure delcustomer(c_id customers.id%type) is begin delete from customers where id = c_id; end delcustomer;
procedure listcustomer is cursor c_customers is select name from customers; type c_list is table of customers.name%type; name_list c_list := c_list(); counter integer :=0; begin for n in c_customers loop counter := counter +1; name_list.extend; name_list(counter) := n.name; dbms_output.put_line(‘customer(’ ||counter|| ‘)’||name_list(counter)); end loop; end listcustomer; end c_package; / 上面的例子中使用嵌套表,我们将在下一章讨论。当上述代码在sql提示符执行时,它产生了以下结果:
package body created. 使用包: 下面的程序使用声明并在包c_package中定义方法。
declare code customers.id%type:= 8; begin c_package.addcustomer(7, ‘rajnish’, 25, ‘chennai’, 3500); c_package.addcustomer(8, ‘subham’, 32, ‘delhi’, 7500); c_package.listcustomer; c_package.delcustomer(code); c_package.listcustomer; end; / 当上述代码在sql提示符执行时,它产生了以下结果:
customer(1): ramesh customer(2): khilan customer(3): kaushik customer(4): chaitali customer(5): hardik customer(6): komal customer(7): rajnish customer(8): subham customer(1): ramesh customer(2): khilan customer(3): kaushik customer(4): chaitali customer(5): hardik customer(6): komal customer(7): rajnish
pl/sql procedure successfully completed
集合是一个有序组具有相同的数据类型的元素。每个元素进行标识的唯一标表示其在集合中的位置。
pl/sql提供了三种集合类型: 索引表或关联数组 嵌套表 可变大小的数组或变长数组
每种类型的集合的以下特征:
集合类型 元素数量 下标类型 密集或稀疏 在哪里创建 可以是对象类型属性 关联数组(或索引表) 无界 字符串或整数 两种都可以 只有在pl/sql块 no 嵌套表 无界 整数 开始密集,可以变得稀疏 无论是在pl/sql块或模式级别 yes 可变大小的数组(变长数组) 有界 整数 总是密集 无论是在pl/sql块或模式级别 yes
这两种类型的pl/sql表即,索引表和嵌套表,都具有相同的结构以及行使用下标符号访问。 然而,这两种类型的表有不同一个方面: 嵌套表可以存储在数据库中的列, 但索引表不能。
索引表 一个索引表(也叫关联数组)是一组键 - 值对。每个键是唯一的,并且用于定位对应的值。键可以是整数或字符串。
使用以下语法创建一个索引表。在这里,我们正在创建一个索引表命名表名, 它的键是subscript_type类型以及对应值为 element_type 类型
type type_name is table of element_type [not null] index by subscript_type;
table_name type_name; 例子: 下面的示例演示如何创建一个表来存储整数值和键名称,它打印的名称相同的列表。
declare type salary is table of number index by varchar2(20); salary_list salary; name varchar2(20); begin – adding elements to the table salary_list(‘rajnish’) := 62000; salary_list(‘minakshi’) := 75000; salary_list(‘martin’) := 100000; salary_list(‘james’) := 78000;
– printing the table name := salary_list.first; while name is not null loop dbms_output.put_line ('salary of ’ || name || ’ is ’ || to_char(salary_list(name))); name := salary_list.next(name); end loop; end; / 当上述代码在sql提示符执行时,它产生了以下结果:
salary of rajnish is 62000 salary of minakshi is 75000 salary of martin is 100000 salary of james is 78000
pl/sql procedure successfully completed. 例子: 一个索引表的元素也可以是任何数据库表字段%type或任何数据库表%rowtype。 下面的例子说明了这个概念。我们将使用存储在数据库中customers表:
select * from customers;
±—±---------±----±----------±---------+ | id | name | age | address | salary | ±—±---------±----±----------±---------+ | 1 | ramesh | 32 | ahmedabad | 2000.00 | | 2 | khilan | 25 | delhi | 1500.00 | | 3 | kaushik | 23 | kota | 2000.00 | | 4 | chaitali | 25 | mumbai | 6500.00 | | 5 | hardik | 27 | bhopal | 8500.00 | | 6 | komal | 22 | mp | 4500.00 | ±—±---------±----±----------±---------+ declare cursor c_customers is select name from customers;
type c_list is table of customers.name%type index by binary_integer; name_list c_list; counter integer :=0; begin for n in c_customers loop counter := counter +1; name_list(counter) := n.name; dbms_output.put_line(‘customer(’||counter|| ‘):’||name_list(counter)); end loop; end; / 当上述代码在sql提示符执行时,它产生了以下结果:
customer(1): ramesh customer(2): khilan customer(3): kaushik customer(4): chaitali customer(5): hardik customer(6): komal
pl/sql procedure successfully completed
嵌套表 嵌套表是就像一个一维数组的元素的数量。然而,嵌套表不同于在以下几方面的数组: 数组具有元素的声明的数量,但嵌套表不用声明大小。嵌套表的大小可以动态地增加。 数组总是密集的,也就是说,它总是有连续的下标。嵌套数组初始是致密,但是删除它的元素时就会变成稀疏。 使用以下语法创建一个嵌套表: type type_name is table of element_type [not null]; table_name type_name; 这个声明是类似声明的索引表中,但没有index by子句。 嵌套表可以被存储在数据库中的列,所以它可用于简化在那里加入一个较大的表中的单个列,使用sql操作。关联数组不能存储在数据库中。 例子: 下面的例子说明使用嵌套表:
declare type names_table is table of varchar2(10); type grades is table of integer;
names names_table; marks grades; total integer; begin names := names_table(‘kavita’, ‘pritam’, ‘ayan’, ‘rishav’, ‘aziz’); marks:= grades(98, 97, 78, 87, 92); total := names.count; dbms_output.put_line(‘total ‘|| total || ’ students’); for i in 1 … total loop dbms_output.put_line(‘student:’||names(i)||’, marks:’ || marks(i)); end loop; end; / 当上述代码在sql提示符执行时,它产生了以下结果:
total 5 students student:kavita, marks:98 student:pritam, marks:97 student:ayan, marks:78 student:rishav, marks:87 student:aziz, marks:92
pl/sql procedure successfully completed. 例子: 嵌套表的元素也可以是任何数据库表字段%type和任何数据库表或%rowtype。下面的例子说明了这个概念。我们将使用存储在数据库中的customers表:
select * from customers;
±—±---------±----±----------±---------+ | id | name | age | address | salary | ±—±---------±----±----------±---------+ | 1 | ramesh | 32 | ahmedabad | 2000.00 | | 2 | khilan | 25 | delhi | 1500.00 | | 3 | kaushik | 23 | kota | 2000.00 | | 4 | chaitali | 25 | mumbai | 6500.00 | | 5 | hardik | 27 | bhopal | 8500.00 | | 6 | komal | 22 | mp | 4500.00 | ±—±---------±----±----------±---------+
declare cursor c_customers is select name from customers;
type c_list is table of customers.name%type; name_list c_list := c_list(); counter integer :=0; begin for n in c_customers loop counter := counter +1; name_list.extend; name_list(counter) := n.name; dbms_output.put_line(‘customer(’||counter||’):’||name_list(counter)); end loop; end; / 当上述代码在sql提示符执行时,它产生了以下结果:
customer(1): ramesh customer(2): khilan customer(3): kaushik customer(4): chaitali customer(5): hardik customer(6): komal
pl/sql procedure successfully completed. 集合方法 pl/sql提供,使集合更容易使用内置集合方法。下表列出了这些方法和用途:
s.n. 方法名称 用途 1 exists(n) 返回true,如果一个集合中的第n个元素的存在;否则返回false 2 count 返回集合当前包含的元素数量 3 limit 检查集合的最大尺寸 4 first 返回在使用整数下标集合的第一个(最小的)索引号 5 last 返回在使用整数下标集合的最后一个(最大的)索引号 6 prior(n) 返回集合中索引n前面的索引号 7 next(n) 返回索引n的下一个索引号 8 extend 追加1个空元素到集合 9 extend(n) 追加n个空元素到集合 10 extend(n,i) 追加的第i个元素的集合的n个拷贝 11 trim 移除集合的末尾一个元素 12 trim(n) 移除一个集合末尾的n个元素 13 delete 移除一个集合中的所有元素,设置计数为0 14 delete(n) 移除关联数组用数字键或嵌套表中的第n个元素。如果关联数组有一个字符串键,对应于该键的值的元素将被删除。如果n为空,delete(n)什么都不做 15 delete(m,n) 除关联数组或嵌套表范围m…n所有元素。如果m大于n或如果m大于或n是零,delete(m,n)什么也不做
集合异常 下表提供了集合异常和引发,当它们:
集合异常 引发情况 collection_is_null 尝试在一个原子空(null)的集合操作 no_data_found 下标指定被删除的元素,或关联数组的一个不存在的元素 subscript_beyond_count 下标超过了一个集合的元素数 subscript_outside_limit 下标超出了允许的范围 value_error 下标为空(null)或不可转换的键类型。如果该键被定义为pls_integer范围,下标是在该范围之外可能会出现这样的异常
数据库事务是一个工作的原子单元,其可以由一个或多个相关的sql语句组成。 所谓的原子性就是数据库的修改所带来的构成事务的sql语句可以集体被提交,即永久到数据库或从数据库中(撤消)回滚。
一个成功执行的sql语句和提交的事务不一样。即使一个sql语句执行成功, 除非包含该语句的事务被提交,但也可以回滚和声明(s)的所有更改可以撤消。
开始/结束事务 事务都有开始和结束。事务开始时有下列事件之一:
连接到数据库后执行的第一个sql语句。 在事务完成之后发出每一个新的sql语句完成。 事务结束时的下列事件之一发生: commit或发出rollback语句。
ddl语句,如create table语句,则发出;因为在这种情况下,commit被自动执行。 一个dcl语句,比如一个grant语句发出; 因为在这种情况下,commit被自动执行。
用户从数据库断开。 从sql* plus用户退出通过发出exit指令,commit自动执行。 sql* plus异常终止,自动执行rollback。
一个dml语句失败; 在这种情况下自动执行撤消dml语句rollback。
提交事务 事务是通过发出sql命令commit永久生效。commit命令的一般语法是:
commit; 示例,
insert into customers (id,name,age,address,salary)values (1, ‘ramesh’, 32, ‘ahmedabad’, 2000.00 ); insert into customers (id,name,age,address,salary)values (2, ‘khilan’, 25, ‘delhi’, 1500.00 ); insert into customers (id,name,age,address,salary)values (3, ‘kaushik’, 23, ‘kota’, 2000.00 ); insert into customers (id,name,age,address,salary)values (4, ‘chaitali’, 25, ‘mumbai’, 6500.00 ); insert into customers (id,name,age,address,salary)values (5, ‘hardik’, 27, ‘bhopal’, 8500.00 ); insert into customers (id,name,age,address,salary)values (6, ‘komal’, 22, ‘mp’, 4500.00 ); commit; 回滚事务 对数据库所做的不提交更改可以使用rollback命令撤消。
rollback命令的一般语法是:
rollback [to savepoint < saveyiibai_name>]; 当一个事务因一些前所未有的情况中止,如系统故障,则整个事务由于提交自动回滚。 如果不使用保存点,然后简单地使用下面的语句来回滚所有的变化:
rollback; 保存点 保存点是某种标志,帮助分裂一个长事务分成更小的单位设置了一些检查点。 由一个长事务中设置保存点,可以根据需要回滚到一个检查点。这是通过发出savepoint命令来完成。
保存点命令的一般语法是:
savepoint < saveyiibai_name >; 示例:
insert into customers (id,name,age,address,salary)values (7, ‘rajnish’, 27, ‘hp’, 9500.00 ); insert into customers (id,name,age,address,salary)values (8, ‘riddhi’, 21, ‘wb’, 4500.00 ); savepoint sav1;
update customers set salary = salary + 1000; rollback to sav1;
update customers set salary = salary + 1000 where id = 7; update customers set salary = salary + 1000 where id = 8; commit; 在这里,rollback to sav1; 声明回滚变化到一点,在那里标志着保存点sav1,之后将开始新的变化。
自动事务控制 要执行一个自动commit在每一个insert,update或delete命令执行时,可以设置autocommit环境变量:
set autocommit on; 可以关闭使用以下命令自动提交模式:
set autocommit off;
提供日期和时间相关的数据类型:
日期时间(datetime)数据类型 间隔数据类型
datetime数据类型有: date timestamp timestamp with time zone timestamp with local time zone
间隔数据类型是: interval year to month interval day to second
日期时间字段值和间隔数据类型 这两个日期时间和间隔数据类型包括字段。这些字段的值确定的数据类型的值。下表列出了时间和间隔的字段及其可能的值。
字段名称 有效日期时间值 有效的间隔值 字段名称 有效日期时间值 有效的间隔值 year -4712 to 9999 (除外0年) 任何非0整数 month 1月12日 0 - 11 day 01 - 31 (受month和year的数值,按日历的区域设置的规则) 任何非0整数 hour 00 - 23 0 - 23 minute 00 - 59 0 - 59 second 00 to 59.9(n), 其中,9(n)是时间小数秒精度,在9(n)的部分是不适用date。 0 to 59.9(n), 其中,9(n)是区间小数秒精度 timezone_hour -12 - 14 (适应范围夏令时更改)date 或 timestamp不适用. 不适用 timezone_minute 00 - 59 date 或 timestamp不适用. 不适用 timezone_region date 或 timestamp不适用. 不适用 timezone_abbr date 或 timestamp不适用. 不适用
下面是日期时间数据类型:
date - 它存储在字符和数字数据类型的日期和时间信息。它是由上世纪,年,月,日,时,分,秒的信息。它被指定为: timestamp - 它是日期数据类型的扩展。它的年,月,日的日期数据类型的存储,以及小时,分钟和秒值。它是用于存储精确的时间值有用。 timestamp with time zone - 它是时间戳的变体,其中包括一个时区区域名称或时区中它的值偏移。时区偏移量是本地的时间和utc之间的差值(以小时和分钟)。此数据类型是用于收集和计算跨越地理区域的最新信息有用。 timestamp with local time zone - 它是时间戳(timestamp )的另一种变型,其中包括一个时区中它的值偏移。
下表列出了日期时间函数(其中,x有日期时间值):
s.n 函数名称 & 描述 1 add_months(x, y); 增加y个月到x 2 last_day(x); 返回该月的最后一天 3 months_between(x, y); 返回x和y之间的月数 4 next_day(x, day); 返回x后第二天的日期时间 5 new_time; 返回从由用户指定的一个时区的时间/天的值 6 round(x [, unit]); x舍入; 7 sysdate(); 返回当前日期时间。 8 trunc(x [, unit]); 截断x
s.n 函数名称 & 描述 1 current_timestamp() 返回包含当前会话时间以及会话时区的时区中的时间戳( timestamp with time zone) 2 extract(( { year | month | day | hour | minute | second } | { timezone_hour | timezone_minute } | { timezone_region | } timezone_abbr ) from x) 从x提取并返回年,月,日,时,分,秒,或时间 3 from_tz(x, time_zone) 通过time_zone指定with timezone一个timestamp时间戳x和时区转换 4 localtimestamp() 返回包含在会话时区的本地时间时间戳 5 systimestamp() 返回含有当前数据库的时间以及数据库时区的时区中的时间戳(timestamp with time zone) 6 sys_extract_utc(x) with timezone x的timestamp转换为包含日期和时间utc时间戳 7 to_timestamp(x, [format]) 将字符串x转换为一个timestamp 8 to_timestamp_tz(x, [format]) 字符串x转换到with timezone时间戳
示例: 下面的代码段示出了使用上述函数功能:
select sysdate from dual; 输出: 08/31/2014 5:25:34 pm
select to_char(current_date, ‘dd-mm-yyyy hh:mi:ss’) from dual; 输出: 31-08-2014 05:26:14
select add_months(sysdate, 5) from dual; 输出: 01/31/2014 5:26:31 pm
select localtimestamp from dual; 输出: 8/31/2014 5:26:55.347000 pm
间隔数据类型和函数 以下是间隔数据类型:
interval year to month - 它存储了一段时间的使用年份和月份日期时间字段 interval day to second - 它存储了一段时间中的天,小时,分钟和秒
select numtoyminterval(100,‘year’) ,numtoyminterval(100,‘month’) —只能到年,月 ,numtodsinterval(100,‘day’) — 可以到 日,时,分,秒 ,numtodsinterval(100,‘hour’) ,numtodsinterval(100,‘minute’) ,numtodsinterval(100,‘second’) from dual;
select extract(year from systimestamp) year ,extract(month from systimestamp) month ,extract(day from systimestamp) day ,extract(hour from systimestamp) hour ,extract(minute from systimestamp) minute ,extract(second from systimestamp) second ,extract(timezone_hour from systimestamp) th ,extract(timezone_minute from systimestamp) tm ,extract(timezone_region from systimestamp) tr ,extract(timezone_abbr from systimestamp) ta from dual ;
year month day hour minute second th tm tr ta
2018 9 13 6 0 4.665942 8 0 unknown unk
间隔函数:
s.n 函数名称 & 描述 1 numtodsinterval(x, interval_unit); 整数x转换为一个间隔(day to second) 2 numtoyminterval(x, interval_unit); x到时间间隔(year to month)数的转换 3 to_dsinterval(x); 将字符串x时间间隔(day to second)到秒转换 4 to_yminterval(x); 将字符串x时间间隔(year to month)转换为整数
select to_yminterval(‘10001010-11’) —to_yminterval的参数要求格式必须是’xx-xx’ ,to_date(‘20110101’,‘yyyymmdd’) ,to_date(‘20110101’,‘yyyymmdd’)+to_yminterval(‘01-11’) from dual ;
select sysdate,to_dsinterval(‘01 00:00:00’)+sysdate as dd from dual select to_char(date ‘2010-02-12’, ‘d’) week_dayth,–周第几天(1-7),星期天=1,星期一=2,星期二=3,星期三=4,星期四=5,星期五=6,星期六=7 to_char(date ‘2010-02-12’, ‘dd’) month_dayth,–月第几天 to_char(date ‘2010-02-12’, ‘ddd’) year_dayth,–年第几天 to_char(date ‘2010-02-12’, ‘day’) weekdayname,–英文星期名 to_char(date ‘2010-02-12’, ‘w’) month_weekth,–月第几周(0-4) to_char(date ‘2010-02-12’, ‘ww’) year_weekth–年第几周(0-53) from dual;
extract(data from datevalue)–返回date的某一部份内容 如果datevalue为date类型,则data可以是(year、month、day) 如果datevalue为timestamp类型,则data可以是(year、month,day、hour、minute、second)
select to_date(‘20110101’,‘yyyymmdd’), to_yminterval(‘02-08’) from dual;
pl/sql允许定义一个对象类型,这有助于在oracle的数据库中设计的面向对象。 对象类型可以包装复合类型。使用对象允许实现数据的具体结构现实世界中的对象和方法操作它。 对象有属性和方法。属性是一个对象的属性,并用于存储对象的状态;和方法被用于模拟其行为。
使用create[or replace] type语句中创建的对象。下面是一个例子,创建包含一些属性的简单的地址对象:
create or replace type address as object (house_no varchar2(10), street varchar2(30), city varchar2(20), state varchar2(10), pincode varchar2(10) ); / 当上述代码在sql提示符执行时,它产生了以下结果:
type created. 让我们来创建一个多个客户对象,包装的属性和方法,拥有面向对象的感觉:
create or replace type customer as object (code number(5), name varchar2(30), contact_no varchar2(12), addr address, member procedure display ); / 当上述代码在sql提示符执行时,它产生了以下结果:
type created. 实例化对象 定义对象类型提供了一个蓝图对象。要使用这个对象,需要创建这个对象的实例。 可以访问属性,使用实例名称和接入操作符,如下对象的方法(.):
declare residence address; begin residence := address(‘103a’, ‘m.g.road’, ‘jaipur’, ‘rajasthan’,‘201301’); dbms_output.put_line('house no: '|| residence.house_no); dbms_output.put_line('street: '|| residence.street); dbms_output.put_line('city: '|| residence.city); dbms_output.put_line('state: '|| residence.state); dbms_output.put_line('pincode: '|| residence.pincode); end; / 当上述代码在sql提示符执行时,它产生了以下结果:
house no: 103a street: m.g.road city: jaipur state: rajasthan pincode: 201301
pl/sql procedure successfully completed.
成员方法 成员方法是用于操纵对象属性。提供的成员方法的声明,同时声明的对象类型。 对象主体限定的代码成员方法。使用create type body语句创建的对象体。
构造函数返回一个新的对象作为其值的功能。 每个对象都有一个系统定义的构造方法。构造方法的名称是相同的对象类型。例如:
residence := address(‘103a’, ‘m.g.road’, ‘jaipur’, ‘rajasthan’,‘201301’); 比较方法被用于比较的对象。有两种方法来比较对象:
映射方法:映射方法它的值取决于属性的值,以这样的方式实现函数。 例如,一个客户对象,如果客户代码是相同的两个客户,可以认为是相同的一个。所以这两个对象之间的关系将取决于代码的值。 顺序方法:顺序方法实现一些内部逻辑比较两个对象。 例如,对于矩形(rectangle)对象,如果其两侧都大,则表示矩形(rectangle)大于另一个矩形(rectangle)。
使用映射方法 让我们试着去了解上面使用下面的矩形对象的概念:
create or replace type rectangle as object (length number, width number, member function enlarge( inc number) return rectangle, member procedure display, map member function measure return number ); / 当上述代码在sql提示符执行时,它产生了以下结果:
type created. 创建类型体:
create or replace type body rectangle as member function enlarge(inc number) return rectangle is begin return rectangle(self.length + inc, self.width + inc); end enlarge;
member procedure display is begin dbms_output.put_line('length: '|| length); dbms_output.put_line('width: '|| width); end display;
map member function measure return number is begin return (sqrt(lengthlength + widthwidth)); end measure; end; / 当上述代码在sql提示符执行时,它产生了以下结果:
type body created. 现在,使用矩形(rectangle)对象及其成员函数:
declare r1 rectangle; r2 rectangle; r3 rectangle; inc_factor number := 5; begin r1 := rectangle(3, 4); r2 := rectangle(5, 7); r3 := r1.enlarge(inc_factor); r3.display;
if (r1 > r2) then – calling measure function r1.display; else r2.display; end if; end; / 当上述代码在sql提示符执行时,它产生了以下结果:
length: 8 width: 9 length: 5 width: 7
pl/sql procedure successfully completed. 使用顺序的方法 现在,相同的效果可以使用顺序方法来实现。让我们用一个顺序方法重新创建矩形(rectangle)对象:
create or replace type rectangle as object (length number, width number, member procedure display, order member function measure(r rectangle) return number ); / 当上述代码在sql提示符执行时,它产生了以下结果:
type created. 创建型类体:
create or replace type body rectangle as member procedure display is begin dbms_output.put_line('length: '|| length); dbms_output.put_line('width: '|| width); end display;
order member function measure(r rectangle) return number is begin if(sqrt(self.lengthself.length + self.widthself.width)> sqrt(r.lengthr.length + r.widthr.width)) then return(1); else return(-1); end if; end measure; end; / 当上述代码在sql提示符执行时,它产生了以下结果:
type body created. 使用矩形(rectangle)对象及其成员函数:
declare r1 rectangle; r2 rectangle; begin r1 := rectangle(23, 44); r2 := rectangle(15, 17); r1.display; r2.display; if (r1 > r2) then – calling measure function r1.display; else r2.display; end if; end; / 当上述代码在sql提示符执行时,它产生了以下结果:
length: 23 width: 44 length: 15 width: 17 length: 23 width: 44
pl/sql procedure successfully completed. 继承pl/sql对象: pl/sql允许从现有的基础对象创建对象。为了实现继承,基本对象应被声明为not final。默认值是final。
下面的程序说明了继承pl/sql对象。让我们创建一个名为tabletop,这是从rectangle对象继承。另一个对象是由基本矩形(rectangle)对象创建:
create or replace type rectangle as object (length number, width number, member function enlarge( inc number) return rectangle, not final member procedure display) not final / 当上述代码在sql提示符执行时,它产生了以下结果:
type created. 创建基本类型主体:
create or replace type body rectangle as member function enlarge(inc number) return rectangle is begin return rectangle(self.length + inc, self.width + inc); end enlarge;
member procedure display is begin dbms_output.put_line('length: '|| length); dbms_output.put_line('width: '|| width); end display; end; / 当上述代码在sql提示符执行时,它产生了以下结果:
type body created. 创建 tabletop 子对象:
create or replace type tabletop under rectangle ( material varchar2(20); overriding member procedure display ) / 当上述代码在sql提示符执行时,它产生了以下结果:
type created. 创造型体的 tabletop 子对象 :
create or replace type body tabletop as overriding member procedure display is begin dbms_output.put_line('length: '|| length); dbms_output.put_line('width: '|| width); dbms_output.put_line('material: '|| material); end display; / 当上述代码在sql提示符执行时,它产生了以下结果:
type body created. 使用 tabletop 对象及其成员函数:
declare t1 tabletop; t2 tabletop; begin t1:= tabletop(20, 10, ‘wood’); t2 := tabletop(50, 30, ‘steel’); t1.display; t2.display; end; / 当上述代码在sql提示符执行时,它产生了以下结果:
length: 20 width: 10 material: wood length: 50 width: 30 material: steel
pl/sql procedure successfully completed. pl/sql抽象对象 not instantiable 子句允许声明一个抽象的对象。不能用一个抽象的对象因为它是抽象的; 必须要创建一个子类型或子类型,以对象使用其功能。
示例,
create or replace type rectangle as object (length number, width number, not instantiable not final member procedure display) not instantiable not final / 当上述代码在sql提示符执行时,它产生了以下结果:
type created.