declare
v_DESC VARCHAR2(30);
v_NUM NUMBER:=45;
v_count BINARY_INTEGER:=0;
v_const constant BINARY_INTEGER :=10;
v_nt VARCHAR2(20) NOT NULL :='lalala';
begin
dbms_output.put_line(v_NUM);
v_NUM:=100;
dbms_output.put_line('v_NUM='||v_NUM);
dbms_output.put_line(v_const);
dbms_output.put_line();
end;
declare
--小数会被截掉
v_num NUMBER(3):=123.2;
--小数点后面保存三位,超过四舍五入,上数点前面肯定只能有一位了,要不然就出错
v_num1 NUMBER(4,3):=2.323;
-- -3 代表小数点前面每几位四舍五入
v_num2 NUMBER(5,-3):=12354.23;
-- P S
--有效数位<=P+|S|
v_num3 NUMBER(4,6):=0.0012345;
----------------------------------------------
--BINARY_INTEGER NUMBER并不是采用二进制形式保存
--在计算之前要进行转化成二进制才能运算
--而BINARY_INTEGER 底层是采用二进制保存的 操作比较快
--只是用于常用(循环)计算,不用与数据库表交互
--varchar2 varcahr 一定给长度
--boolean true false
--DATE TIMSTAMP 日间戳 INTERVAL
begin
dbms_output.put_line(v_num); --123
dbms_output.put_line(v_num1); --2.323
dbms_output.put_line(v_num2); --12000
dbms_output.put_line(v_num3); --.001235
end;
--将数据库表中的数据取出来放在变量中
--注意声明的变量 要和数据表字段类型一致
declare
v_id number(7);
v_fname varchar2(25); --当我们不知道表结构,或表结构变化时会出错长度不够的隐患
v_salary number(11,2);
begin
select id,first_name,salary into v_id,v_fname,v_salary from s_emp where id=1;
dbms_output.put_line(v_id||' '||v_fname||' '||v_salary);
end;
--解决上面的问题 使用TYPE方式的变量
declare
v_id s_emp.id%TYPE;
v_fname s_emp.first_name%TYPE; --声明一个TYPE类型
v_salary s_emp.salary%TYPE;
begin
select id,first_name,salary into v_id,v_fname,v_salary from s_emp where id=1;
dbms_output.put_line(v_id||' '||v_fname||' '||v_salary);
end;
--把一组相关的变量放在一起
declare
TYPE record_emp IS RECORD(
v_id s_emp.id%TYPE,
v_fname s_emp.first_name%TYPE,
v_salary s_emp.salary%TYPE
);
v_temp record_emp;
begin
select id,first_name,salary into v_temp from s_emp where id=1;
dbms_output.put_line(v_temp.v_id||' '||v_temp.v_fname||' '||v_temp.v_salary);
end;
--类型赋值
declare
TYPE record_emp IS RECORD(
v_id s_emp.id%TYPE,
v_fname s_emp.first_name%TYPE,
v_salary s_emp.salary%TYPE
);
TYPE record_emp1 IS RECORD(
v_id s_emp.id%TYPE,
v_fname s_emp.first_name%TYPE,
v_salary s_emp.salary%TYPE
);
v_temp record_emp;
v_temp1 record_emp;
v_temp2 record_emp1;
--注意 同类型可以赋值 不同类型即使结构相同也不能赋值
begin
select id,first_name,salary into v_temp from s_emp where id=1;
dbms_output.put_line(v_temp.v_id||' '||v_temp.v_fname||' '||v_temp.v_salary);
end;
---RWOTYPE 类型
--查询整个表的所有字段内容
--按照上面的定义就太麻烦了
--同样也存在一定隐患,如果表字段增加了,就会出现问题
declare
v_emp s_emp%ROWTYPE;
begin
select * into v_emp from s_emp where id=1;
dbms_output.put_line(v_emp.first_name||' '||v_emp.last_name);
end;
--TABLE 类型的使用
--关于程序中100 2000 没有什么要求 是一个整型数据
declare
--声明一个TABLE类型
TYPE t_emp IS TABLE OF s_emp%ROWTYPE INDEX BY BINARY_INTEGER;
v_emp t_emp;
begin
select * into v_emp(100) from s_emp where id=1;
select * into v_emp(2000) from s_emp where id=2;
dbms_output.put_line(v_emp(100).first_name);
dbms_output.put_line(v_emp(2000).first_name);
end;
--SQL块嵌入
--变量尽量不要重名
<<Outer>>
declare
v_Num number:=100;
begin
v_Num:=1;
declare
v_Str varchar2(20):='hello';
v_Num number :=200;
begin
dbms_output.put_line('v_Str:'||v_Str);
dbms_output.put_line('v_Num:'||v_Num);
dbms_output.put_line('v_Num:'||Outer.v_Num);
end;
dbms_output.put_line('v_Num:'||v_Num);
end;
---条件表达式
--条件为null 或 fasle 都是false 是意思
--只能是true 的情况才执行代码
IF boolean类型表达式 THEN
ELSE
END IF:
------------------------
IF THEN
ELSE IF ..... THEN
ELSE
END IF;
-------------------------
declare
v_flag boolean;
begin
if v_flag then
dbms_output.put_line('TRUE');
elseif (not v_flag) then
dbms_output.put_line('FALSE');
else
dbms_output.put_line('NULL');
end if;
end;
declare
v_sal s_emp.salary%TYPE;
v_bonus number(10,2);
begin
select salary into v_sal from s_emp where id=1;
if v_sal>1500 then
v_bonus:=v_sal*0.2;
elsif v_sal > 1000 then
v_bonus:=v_sal*0.1;
else
v_bonus:=v_sal*0.05;
end if;
end;
--循环 LOOP
LOOP
--EXIT WHEN boolean_exp
IF boolean_exp THEN
EXIT;
END IF;
END LOOP;
declare
v_ret number:=0;
i number:=1;
begin
loop
v_ret :=v_ret+1;
i:=i+1;
dbms_output.put_line(v_ret);
exit when i>100;
end loop;
end;
---WHILE 循环
WHILE boolean_exp LOOP
--循环体
END LOOP;
declare
v_ret binary_integer:=0;
begin
while v_ret<100 loop
v_ret:=v_ret+1;
dbms_output.put_line(v_ret);
end loop;
end;
--查询前五个员工的姓名
declare
TYPE t_emp IS TABLE OF s_emp%ROWTYPE INDEX BY BINARY_INTEGER;
v_emp t_emp;
v_cnt BINARY_INTEGER :=1;
begin
loop
select * into v_emp(v_cnt) from s_emp where id=v_cnt;
v_cnt :=v_cnt+1;
exit when v_cnt>5;
end loop;
v_cnt :=1;
while v_cnt<=5 loop
dbms_output.put_line(v_emp(v_cnt).first_name||' '||v_emp(v_cnt).last_name);
v_cnt :=v_cnt+1;
end loop;
end;
--FOR 循环 FROM loop_count IN [REVERSE] low_bound..high_bound LOOP
-- ...........
-- END LOOP;
--使用FOR循环重写上面的例子
declare
TYPE t_emp IS TABLE OF s_emp%ROWTYPE INDEX BY BINARY_INTEGER;
v_emp t_emp;
v_cnt BINARY_INTEGER :=1;
begin
FOR v_cnt IN 1..5 LOOP
select * into v_emp(v_cnt) from s_emp where id=v_cnt;
END LOOP;
FOR v_cnt IN REVERSE 1..5 LOOP
dbms_output.put_line(v_emp(v_cnt).first_name||' '||v_emp(v_cnt).last_name);
END LOOP;
end;
--记数器不用声明 类型就是:BINARY_INTEGER 类型
-- IN 后面加 REVERSE 表示循环的方向 如:从1-5 或从 5-1
--编程时不使用goto 语句
NULL --可以列表空语句
-- 可以写在PL/SQL 中的语句
-- 只胡DML 和 事务控制语句可以写在PL/SQL程序中
--DBMS_SQL 本地动态SQL包
--可以使用DBMS_SQL 包执行DDL之类的语句
declare
v_str varchar2(200);
begin
v_str :='create table lilp_temp(id number,coll varchar2(20))';
execute immediate v_str;
end;
--速度比较慢 常用函数[ ]
declare
v_date varchar2(50);
begin
v_date :=to_char(sysdate,'yyyy-mm-dd hh24:mi:ss');
dbms_output.put_line(v_date);
end;
---游标的使用 CURSOR
-- 使用游标 [显式|隐式游标]
-- 1.声明游标 CURSOR cursor_name IS SELECT_STATEMENT;
-- 2.打开游标 OPEN cursor_name ;
-- 3.结果处理 FETCH cursor_name INTO var1;
-- FETCH cursor_name INTO record_var;
-- 4.关闭游标 CLOSE cursor_name;
declare
v_deptId s_emp.dept_id%type :=41;
v_emp s_emp%rowtype;
cursor our_emp is
select * from s_emp where dept_id=v_deptId;
begin
open our_emp;
--必须先取一次,才能判断,根据%FOUND 的意思
fetch our_emp into v_emp;
while our_emp%FOUND loop
dbms_output.put_line(v_emp.id ||' '||v_emp.first_name);
fetch our_emp into v_emp;
end loop;
close our_emp;
dbms_output.put_line('--------------------------------------------');
open our_emp;
loop
fetch our_emp into v_emp;
exit when our_emp%NOTFOUND;
dbms_output.put_line(v_emp.id ||' '||v_emp.first_name);
end loop;
close our_emp;
dbms_output.put_line('--------------------------------------------');
--不处打开游标
FOR v_emp1 IN our_emp LOOP
dbms_output.put_line(v_emp1.id ||' '||v_emp1.first_name);
END LOOP;
close our_emp;
end;
declare
v_deptId s_emp.dept_id%type :=41;
cursor our_emp is
select * from s_emp where dept_id=v_deptId;
begin
--不处打开关闭游标
FOR v_emp IN our_emp LOOP
dbms_output.put_line(v_emp.id ||' '||v_emp.first_name);
END LOOP;
end;
--循环取数据,如何控制循环条件å
-- %FOUND 如何FETCH 返回一行数据,则返回TRUE ,否则就返回false; 如果游标未打开,就检查%FOUND
-- %NOTFOUND --与%FOUND 相反 上一次游标撮的结果,如果上一次FECTH 到数据,就返回 FALSE,否则就返回true
-- %ISOPEN 判断游标是否打开
--游标参数不能加精度
declare
cursor cur_emp(p_did s_emp.dept_id%type) is
select * from s_emp where dept_id=p_did;
v_emp s_emp%rowtype;
begin
open cur_emp(41);
loop
fetch cur_emp into v_emp;
exit when cur_emp%NOTFOUND;
dbms_output.put_line(v_emp.id ||' '||v_emp.first_name);
end loop;
dbms_output.put_line('--------------------------------------------');
close cur_emp;
FOR v_emp1 IN cur_emp(41) LOOP
dbms_output.put_line(v_emp1.id ||' '||v_emp1.first_name);
END LOOP;
end;
--异常处理
e_expname exception; 声明异常
raise e_expname; 抛出异常
when e_expname then 异常处理
declare
v_emp s_emp%rowtype;
begin
select * into v_emp from s_emp where id=100;
dbms_output.put_line(v_emp.first_name);
exception
when NO_DATA_FOUND then
dbms_output.put_line('没有找到数据!');
end;
--自定义异常
declare
e_myException exception;
v_emp s_emp%rowtype;
begin
select * into v_emp from s_emp where id=12;
if v_emp.salary >1000 then
raise e_myException;
end if;
dbms_output.put_line(v_emp.salary);
exception
when no_data_found then
dbms_output.put_line('没有找到数据');
when e_myException then
dbms_output.put_line('工资太低!');
--update s_emp set salary=salary+1000 where id=v_emp.id;
when others then
dmbs_output.put_line('其它异常');
end;
--之前写的代码块无法利用,现在考虑对代码块进行复用
--存储过程
create or replace procedure lilp_proc_hello as
--声明部分
begin
dbms_output.put_line('hello nihao!');
end;
-- 调用存储过程
begin
lilp_proc_hello;
end;
create or replace procedure lilp_proc_hello(p_id s_emp.id%type) as
--声明部分
v_emp s_emp%rowtype;
begin
select * into v_emp from s_emp where id=p_id;
dbms_output.put_line(v_emp.first_name);
end;
begin
lilp_proc_hello(11);
end;
--参数模式 IN OUT IN OUT
create or replace procedure lilp_proc_hello(
p_id s_emp.id%type,
p_name OUT s_emp.first_name%type
) as
--声明部分
v_emp s_emp%rowtype;
begin
select * into v_emp from s_emp where id=p_id;
p_name:=v_emp.first_name;
end;
declare
v_name s_emp.first_name%type;
begin
lilp_proc_hello(1,v_name);
dbms_output.put_line(v_name);
end;
--out 参数从存储过程内部传值出来,并不会所值带到存储过程中
--int 模式的参数只能传值到存储过程中,并不以从存储过程中带值出来
--in out 模式的参数即可以写操作也可以做读操作
--存储形参声明时不要指定长度
--形参可以使用默认值 可以使用名字标识法
--FUNCTION 一定要有 return 语句
create or replace function lilp_fun_add(
p_a number,
p_b number
)return number is
v_ret number;
begin
v_ret:=p_a+p_b;
return v_ret;
end;
declare
v_ret number;
begin
v_ret:= lilp_fun_add(2,3);
dbms_output.put_line(v_ret);
end;
--包 package
--包规范 [ 声明变量 类型 异常 游标 存储过程 函数] 和 名实体[实现] 独立存在于数据当中
create or replace package pack_emp as
v_emp s_emp%rowtype;
procedure addEmp(p_emp s_emp%rowtype);
end pack_emp;
create or replace package body pack_emp as
procedure addEmp(p_emp s_emp%rowtype) as
begin
insert into s_emp(id,last_name,first_name,salary) values(p_emp.id,p_emp.last_name,p_emp.first_name,p_emp.salary);
commit;
end;
end pack_emp;
--调用 某个包下面的存储过程
declare
begin
pack_emp.v_emp.id:=56;
pack_emp.v_emp.last_name:='lala';
pack_emp.v_emp.first_name:='hehe';
pack_emp.v_emp.salary:=2000;
pack_emp.addEmp(pack_emp.v_emp);
end;
--声明重载
create or replace package pack_emp as
procedure addEmp(p_emp s_emp%rowtype);
procedure addEmp(p_name,s_emp.first_name%type);
procedure addEmp();
end pack_emp;
--类型要不是不同的类型系列