--设置数据库输出,默认为关闭,每次新打开窗口都要重新设置 set serveroutput on --调用 包 函数 参数 execute dbms_output.put_line('hello world'); --或者用call调用,相当于java中的调试程序打桩 call dbms_output.put_line('hello world'); --pl语句块是pl/sql里最小的编程块,其中可以再嵌套begin end begin dbms_output.put_line('Hello World'); dbms_output.put_line('2*3='||(2*3)); dbms_output.put_line('what''s'); end; --如何声明变量,所有变量必须再declare中声明,程序中不允许声明 --没有初始化的变量默认值为null,屏幕上null是看不见的,命名习惯:一般变量以v_开头 --注意number也能存小数,最长38位,所以以后建议整数都用binary_integer存 --long是字符类型,boolean类型补能打印 --标准变量类型:数字,字符,时间,布尔 declare v_number1 number ; v_number2 number(3,2) ; v_number3 binary_integer :=1; v_name varchar2(20) :='kettas'; v_date date :=sysdate; v_long long :='ni hao'; v_b boolean := true; begin if (v_number1 is null) then dbms_output.put_line( 'hello'); end if; dbms_output.put_line(v_number1); dbms_output.put_line(v_number2); dbms_output.put_line(v_number3); dbms_output.put_line(v_name); dbms_output.put_line(v_date); dbms_output.put_line(v_long); --dbms_output.put_line(v_b); end; / --组合类型:record table --record类型最常用,声明的时候可以加not null,但必须给初始值 --如果record类型一致可以相互赋值,如果类型不同,里面的字段恰好相同,不能互相赋值 declare type t_first is record( id number(3), name varchar2(20) ); v_first t_first; begin v_first.id:=1; v_first.name:='ws'; dbms_output.put_line(v_first.id); dbms_output.put_line(v_first.name); end; / --考虑一下,oracle中赋值方式是拷贝还是引用方式 declare --v_number1 number:=1; --v_number2 number; type t_first is record( id number, name varchar2(20) ); v_first t_first; v_second t_first; begin --v_number2:=v_number1; --v_number1:=2; --dbms_output.put_line(v_number1); --dbms_output.put_line(v_number2); v_first.id:=1; v_first.name:='susu'; --v_second:=v_first; v_second.id:=v_first.id; v_second.name:=v_first.name; v_first.id:=2; v_first.name:='kettas'; dbms_output.put_line(v_first.id); dbms_output.put_line(v_first.name); dbms_output.put_line(v_second.id); dbms_output.put_line(v_second.name); end; / ------------------------- --table类型,相当于java中的map,就是一个可变长的数组,key必须是整数,可以是负数,value可以是标量,也可以是record --可以不按顺序赋值,但必须先赋值后使用 declare type t_tb is table of varchar2(20) index by binary_integer; v_tb t_tb; begin v_tb(100):='hello'; v_tb(98):='world'; dbms_output.put_line(v_tb(100)); dbms_output.put_line(v_tb(98)); end; declare type t_rd is record(id number,name varchar2(20)); type t_tb is table of t_rd index by binary_integer; v_tb2 t_tb; begin v_tb2(100).id:=1; v_tb2(100).name:='hello'; --dbms_output.put_line(v_tb2(100).id); --dbms_output.put_line(v_tb2(100).name); dbms_output.put_line(v_tb2(100).id||' '||v_tb2(100).name); end; / --%type 和 %rowtype 以及如何从数据库把数据取回来 create table student33( id number, name varchar2(20), age number(3,0) ); insert into student(id,name,age) values(1,'susu',23); --查找一个字段的变量 declare v_name varchar2(20); v_name2 student.name%type; begin select name into v_name2 from student33 where rownum=1; dbms_output.put_line(v_name2); end; / --查找多个字段的变量 declare v_id student33.id%type; v_name student33.name%type; v_age student33.age%type; begin select id,name,age into v_id,v_name,v_age from student33 where rownum=1; dbms_output.put_line(v_id||' '||v_name||' '||v_age); end; / --查找一个类型的变量,推荐用* declare v_student student33%rowtype; begin select * into v_student from student33 where rownum=1; dbms_output.put_line(v_student.id||' '||v_student.name||' '||v_student.age); end; / --也可以按字段查找,但是字段顺序必须一样,不推荐这样做 declare v_student student33%rowtype; begin select id,name,age into v_student from student33 where rownum=1; dbms_output.put_line(v_student.id||' '||v_student.name||' '||v_student.age); end; / declare v_student student33%rowtype; begin select id,name,age into v_student.id,v_student.name,v_student.age from student33 where id=1; --select * into v_student.id,v_student.name,v_student.age from student33 where id=1; dbms_output.put_line(); end; / --注意:insert,update,delete,select都可以,create table,drop table不行 --dpl,dml,和流程控制可以在pl/sql里用,ddl不行 declare v_name student33.name%type:='wang'; begin insert into student33(id,name,age) values(2,v_name,26); end; / --下边这种方式也可以 begin insert into student33(id,name,age) values(5,'hehe',25); end; / declare v_name student.name%type:='hexian'; begin update student set name=v_name where id=1; end; / begin update student33 set name='qinaide' where id=2; end; / --delete begin delete from student33 where id=5; end; / --变量的可见空间 declare v_i1 binary_integer:=1; begin declare v_i2 binary_integer:=2; begin dbms_output.put_line(v_i1); dbms_output.put_line(v_i2); end; dbms_output.put_line(v_i1); --dbms_output.put_line(v_i2); end; / ------------------------流程控制 --if判断 declare v_b boolean:=true; begin if v_b then dbms_output.put_line('ok'); end if; end; / --if else declare v_b boolean:=true; begin if v_b then dbms_output.put_line('ok'); else dbms_output.put_line('false'); end if; end; / --if elsif else declare v_name varchar2(20):='ws'; begin if v_name='0701' then dbms_output.put_line('0701'); elsif v_name='ws' then dbms_output.put_line('ws'); else dbms_output.put_line('false'); end if; end; / --loop循环,注意推出exit是推出循环,而不是推出整个代码块 declare v_i binary_integer:=0; begin loop if v_i>10 then exit; end if; v_i:=v_i+1; dbms_output.put_line('hehe'); end loop; dbms_output.put_line('over'); end; / --更简单的写法 declare v_i binary_integer :=0; begin loop exit when v_i>10; v_i :=v_i+1; dbms_output.put_line('hehe'); end loop; dbms_output.put_line('over'); end; / --while循环 declare v_i binary_integer:=0; begin while v_i<10 loop dbms_output.put_line('hello'||v_i ); v_i:=v_i+1; end loop; dbms_output.put_line('over'); end; / --for循环,注意不需要声明变量 begin for v_i in 0..10 loop dbms_output.put_line('hello'||v_i); end loop; dbms_output.put_line('over'); end; / --练习1用循环往student里插入30条记录 --要求:id为0,1,2... -- name为kettas0,kettas1,kettas2... -- age为11,12,13... --练习2,假设不知道数据库里的数据规则和数量, --把所有的student33数据打印到终端 --问题1答案 declare v_student student33%rowtype; begin delete from student33; for v_i in 0..20 loop insert v_student into student33(id,name,age) values(v_i,'kettas'||v_i,10+v_i); end loop; end; / --也可以这样 begin delete from student33; for v_i in 0..20 loop insert into student33 values(v_i,'susu'||v_i,18+v_i); end loop; end; --问题2答案 --rownum是伪列,在表里没有 --数据库先是执行from student33遍历student33表,如果没有where条件过滤,则先做成一个结果集,然后再看select --后面的条件挑出合适的字段形成最后的结果集,如果有where条件,则不符合条件的就会从第一个结果集中删除 --后面的数据继续加进来判断,所以如果直接写rownum=2,或者rownum>10这样的语句就查不出数据 --可以用一个子查询解决 select rownum,id from student33 where rownum=2; declare v_number binary_integer; v_student student33%rowtype; begin select count(*) into v_number from student33; for i in 1..v_number loop select id,name,age into v_student from( select rownum rn,id,name,age from student33 )where rn=i; dbms_output.put_line('id: '||v_student.id||' name:'||v_student.name); end loop; end; --异常的定义使用 begin dbms_output.put_line(1/0); exception when others then dbms_output.put_line('error'); end; declare e_myException exception; begin dbms_output.put_line('hello'); raise e_myException;--raise抛出异常,用此关键字向外抛异常 dbms_output.put_line('world'); dbms_output.put_line(1/0); exception when e_myException then dbms_output.put_line(sqlcode);--当前会话执行状态,错误编码 dbms_output.put_line(sqlerrm);--当前错误信息 dbms_output.put_line('my error'); when others then dbms_output.put_line('error'); end; --error表,每次有异常可以加到表里,相当于log日志 --id,code,errm,information,create date --目前先这么写,学完存储过程后再改成一个过程,用的时候只需要调用即可 drop table error; create table error( id number, code number, errm varchar2(4000), information varchar2(4000), create_date date ); drop sequence my_key; create sequence my_key; insert into error values(my_key.nextVal,1,'xxx','xxxxx',sysdate); --具体做法 declare e_myException exception; begin dbms_output.put_line('hello'); raise e_myException; dbms_output.put_line('world'); dbms_output.put_line(1/0); exception when e_myException then declare v_code binary_integer; v_errm varchar2(4000); begin v_code:=sqlcode; v_errm:=sqlerrm; insert into error values(my_key.nextVal,v_code,v_errm,'e_myException',sysdate); end; when others then dbms_output.put_line('error'); end; / --cursor 游标(结果集)用于提取多行数据 --定义后不会有数据,使用后才有 --一旦游标被打开,就无法再次打开(可以先关闭,再打开) declare cursor c_student is select * from student33; begin open c_student; close c_student; end; --第二种游标的定义方式,用变量控制结果集的数量 declare v_id binary_integer; cursor c_student is select * from student33 where id>v_id; begin v_id:=10; open c_student; close c_student; end; / --第三种游标的定义方式,带参数的游标,用的最多 declare cursor c_student(v_id binary_integer) is select * from student33 where id>v_id; begin open c_student(10); close c_student; end; / --游标的使用,一定别忘了关游标 declare v_student student33%rowtype; cursor c_student(v_id binary_integer) is select * from student33 where id>v_id; begin open c_student(10); fetch c_student into v_student; close c_student; dbms_output.put_line(v_student.name); end; --如何遍历游标fetch --游标的属性 %found,%notfound,%isopen,%rowcount --%found:若前面的fetch语句返回一行数据,则%found返回true,如果对未打开的游标使用则报ORA-1001异常 --%notfound,与%found行为相反 --%isopen,判断游标是否打开 --%rowcount:当前游标的指针位移量,到目前位置游标所检索的数据行的个数,若未打开就引用,返回ORA-1001 --loop方式遍历游标 declare v_student student33%rowtype; cursor c_student(v_id binary_integer) is select * from student33 where id>v_id; begin open c_student(10); loop fetch c_student into v_student; exit when c_student%notfound; dbms_output.put_line('name:'||v_student.name); end loop; close c_student; end; --while循环遍历游标,注意,第一次游标刚打开就fetch,%found为null,进不去循环 --如何解决:while nvl(c_student%found,true) loop declare v_student student33%rowtype; cursor c_student(v_id binary_integer) is select * from student33 where id>v_id; begin open c_student(10); while c_student%found is null or c_student%found loop fetch c_student into v_student; dbms_output.put_line('name:'||v_student.name); end loop; close c_student; end; --for循环遍历,最简单,用的最多,不需要声明v_student,打开关闭游标,fetch declare cursor c_student(v_id binary_integer) is select * from student33 where id>v_id; begin for v_student in c_student(10) loop dbms_output.put_line('name:'||v_student.name); end loop; end; --goto例子,不推荐使用goto,会使程序结构变乱 declare i binary_integer:=0; begin if i=0 then goto hello;end if; <<hello>> begin dbms_output.put_line('hello'); goto over; end; <<world>> begin dbms_output.put_line('world'); goto over; end; <<over>> dbms_output.put_line('over'); end; --pl/sql day2 --存储过程:把匿名块存储下来 --匿名块运行后不会在数据库留下 declare v_content varchar2(4000):='hello'; begin dbms_output.put_line(v_content); end; --创建或修改一个过程,ws_println(形式参数,声明类型即可),as可以替换成is --变量可以声明在as和begin之间 create or replace procedure ws_println(v_content varchar2) as begin dbms_output.put_line(v_content); end; --调用有参过程 execute ws_println('ws'); call ws_println('ws'); begin ws_println('ws'); end; --删除一个过程 drop procedure ws_println; --查看数据库里的过程 select * from user_procedures; select object_name,procedure_name from user_procedures; desc user_procedures; --procedure里可以调用其它的procedure create or replace procedure say_hello is begin ws_println('hello'); end; --或者这样也可以 create or replace procedure say_hello as begin ws_println('hi susu'); end; --调用无参过程的方式: execute say_hello; call say_hello(); begin say_hello; end; --一个参数的存储过程 --输入参数in,输入参数不能进行赋值,默认不写就是in --存储过程没有重载,这个有参的say_hello会替代上面的无参say_hello create or replace procedure say_hello(v_name in varchar2) as begin --v_name:='a'; ws_println('hello '||v_name); end; --调用有参的存储过程的两种方式 begin say_hello('susu');--方式1 say_hello(v_name=>'xianbin');--方式2 end; --多个参数的存储过程 create or replace procedure say_hello (v_first_name in varchar2,v_last_name in varchar2) as begin ws_println('hello '||v_first_name||'.'||v_last_name); end; --调用多个参数的两种方式 --方式一,这种方式需按顺序给出值,否则出现异常 begin say_hello('he','susu'); end; --方式二,用指定型参名的方式调用可以不按顺序赋值 begin say_hello(v_last_name=>'he',v_first_name=>'susu'); end; --out输出参数,用于利用存储过程给一个或多个变量赋值,类似于返回值 create or replace procedure say_hello (v_name in varchar2,v_content out varchar2) begin v_content:='hello'||v_name; end; --调用 declare v_con varchar2(200); v_in varchar2(20):='wang'; begin say_hello(v_in,v_con); ws_println(v_con); end; --in out参数,既赋值,又取值 create or replace procedure say_hello(v_name in out varchar2) as begin v_name:='hi '||v_name; end; --调用 declare v_inout varchar2(20):='wangsu'; begin say_hello(v_inout); ws_println(v_inout); end; --缺省参数 create or replace procedure say_hello(v_name varchar2 default 'susu',v_content varchar2 default 'hello') as begin ws_println(v_name||' '||v_content); end; --调用,用指明形参名的方式调用更好 begin say_hello(); end; begin say_hello(v_name=>'wangsu'); end; begin say_hello(v_content=>'hi'); end; --function函数 --过程和函数都以编译后的形式存放在数据库中,函数可以没有参数也可以有多个参数并有一个返回值。过程 --有零个或多个参数,没有返回值。函数和过程都可以通过参数列表接收或返回零个或多个值,函数和过程的 --主要区别不在于返回值,而在于他们的调用方式,过程是作为一个独立执行语句调用的,函数以合法的表达 --式的方式调用 create or replace function func(v_name in varchar2) return varchar2 is begin return(v_name||' hello'); end; --调用 declare v_name varchar2(20); begin v_name:=func('susu'); ws_println(v_name); end; --out 参数的函数 create or replace function func(v_name in varchar2,v_content out varchar2) return varchar2 is begin v_content:=v_name||' hello'; return v_content; end; --调用 declare v_name varchar2(20); v_name1 varchar2(20); begin v_name1:=func('susu',v_name); ws_println(v_name); ws_println(v_name1); end; --in out 参数 create or replace function func(v_name in out varchar2) return varchar2 is begin v_name:=v_name||' hello'; return 'ws'; end; --调用 declare v_inout varchar2(20):='world'; v_ret varchar2(20); begin v_ret:=func(v_inout); ws_println(v_inout); ws_println(v_ret); end;