函数
函数可以return,过程不可以,过程可以out,函数也可以out,不过基本不用
create function 函数名
(参数)
return 返回数据类型
is
begin
end;
将一个函数创建两次,第二次覆盖第一次,不会报该函数已存在的错,加 or replace
create or replace function 函数名
(参数)//个数不受限制
return 返回数据类型//不写长度
is//定义临时变量,没有可以不写
begin
end;
定义函数
create or replace function f_sun
(
v_a number,v_b number
)
return number
is
begin
return nvl(v_a,0)+nvl(v_b,0);
end;
传参
select f_sun(3,5) from dual;
select ename,f_sun(sal,comm) from emp;
练习
新闻表,新闻标题
varchar 一个汉字占2个字符
nvarchar 一个汉字占1个字符
标题超过15个字符显示前12个加。。。
create or replace function f_char
(
v_a nvarchar2
)
return nvarchar2
is
begin
if length(v_a)<15 then
return v_a;
else
return (substr(v_a,1,12)||'...');
end if;
end;
select f_char('我问问合并数据为i会晤i我去哦就爱看苍穹i额u发') from dual;
方法2:
create or replace function f_char
(
v_a nvarchar2,len num
)
return nvarchar2
is
begin
if length(v_a)
过程
1、不带参数
create or replace procedure p_addsal
is
begin
update emp set sal=sal+100;
end;
exec p_addsal;
//执行
//没有限制过程结果
2、有参数有结果
create or replace procedure p_getsal
(
v_deptno in number,--//执行需要的参数
v_maxsal out number,--//保存执行的结果
v_minsal out number
)
is
begin
select max(sal),min(sal) into v_maxsal,v_minsal from emp where deptno=v_deptno;
end;
//执行过程
declare
v_max emp.sal%type;
v_min emp.sal%type;
begin
p_getsal(&deptno,v_max,v_min);
dbms_output.put_line('最高工资'||v_max||' 最低工资'||v_min);
end;
练习
根据职位查询该职位的最高工资的姓名和最低工资的姓名
create or replace procedure p_getname
(
v_job in varchar2,
v_maxsalename out varchar2,
v_minsalename out varchar2
)
is
begin
select ename into v_maxsalename from emp where sal=(select max(sal) from emp where job=v_job);
select ename into v_minsalename from emp where sal=(select min(sal) from emp where job=v_job);
end;
//执行
declare
v_maxsalname emp.ename%type;
v_minsalname emp.ename%type;
begin
p_getname(&job,v_maxsalname,v_minsalname);
dbms_output.put_line(v_maxsalname||' '||v_minsalname);
end;
--//set serveroutput on;打开输出
输入输出型参数
in out 既可以输入也可以输出
根据员工编号查询他的工资
create or reolace procedure p_getsal
(
v_emono in out number
)
is
begin
select sal into v_empno from emp where empno=v_empvo;
end;
declare
v_empno number(10);
begin
v_emp:=7788;
p_getsal(v_empno);
dbms_output.put_line('工资'||v_empno);
end;
返回结果是游标
系统中有定义好的动态游标(弱类型)sys_refcursor
根据部门编号查本部门的员工姓名,职位,薪水
create or replace procedure p_getemp
(
v_deptno in number,
v_result out sys_refcursor
)
is
begin
open v_result for select ename,job,sal from emp where deptno=v_deptno;
end;
//调用要定义游标
declare
mycur sys_recursor;
type t_record is record
(
v_name emp.ename%type,
v_job emp.job%type,
v_sal emp.sal%type,
);
v_row t_record;
begin
p_getemp(&deptno,mycur);
loop
fetch mycur into v_row;
exit when mycur%notfound;
dbms_output.put_line(v_row.v_name||' '||v_row.v_job||' '||v_row.v_sal);
end loop;
close mycur;
end;
练习
输入季节 to_char(q),返回这个季节入职的员工姓名,职位,部门名称
create or replace procedure p_getemp
(
v_jijie in varchar2,
v_result out sys_refcursor
)
is
begin
open v_result for select ename,job,dname from emp
inner join dept on dept.deptno=emp.deptno where hiredate in(
select hiredate from emp where decode(to_char(hiredate,'q'),1,'春',2,'夏',3,'秋',4,'冬')=v_jijie);
-----------------------------------to_char(hiredate,'q')=instr('春夏秋冬','春');
end;
declare
mycur sys_refcursor;
type t_record is record
(
v_ename emp.ename%type,
v_job emp.job%type,
v_dname dept.dname%type
);---一个类型
v_row t_record;--通过类型可定义变量
begin
p_getemp(&v_jijie,mycur);
loop
fetch mycur into v_row;
exit when mycur%notfound;
dbms_output.put_line(v_row.v_ename||' '||v_row.v_job||' '||v_row.v_dname);
end loop;
close mycur;
end;
触发器
行级
表级
按时间可分为:before,after
insert,update,delete
触发之后不能调用
满足某些条件之后自动触发
create or replace trigger <触发器名>
引发异常:raise_application_error(-20000到20000)
特殊变量
:new---------------引用最新的列值 增加的 修改之后的 数据
:old-----------------引用以前的列 删除的 修改之前的 数据
update 某一列数据时才会使用 ,of 列名 on 表名
insert,delete更新的都是一行数据,直接 ,on 表名
of 列名 不写表示对整个表的所有列
只允许15号修改工资
create trigger tr_before_update_emp_sal
before update of sal on emp
for each row --//有几行数据,触发几次,没有这句话,只触发一次触发器
declare
begin
if to_number(to_char(sysdate,'dd'))<>15 then
--//引发异常
raise_application_error(-20001,'今天不允许修改工资');
end if;
end;
update emp set sal=sal+100;
练习
账户表
账户,密码,用户名,开户日期,余额
10086,123456,中国移动,2019-7-10,10000
交易表
账户,交易时间,类型,金额,备注
10086,2019-7-12,存入,500,零花钱
create table account
(accid number(10) not null,
password varchar2(20) not null,
username varchar2(20) not null,
opendate date not null,
balance number(10,2)
)
create table trade
(
accid number(10) not null,
tradedate date not null,
tradetype varchar(10) not null,
money number(10,2) not null,
remark number(20)
)
insert into account values(10086,'123456','中国移动',sysdate,10000);
create or replace trigger tr_after_insert_trade
after insert on trade
for each row
declare
begin
if :new.tradetype='存入' then
update account set balance=balance+:new.money where accid=:new.accid;
else
update account set balance=balance-:new.money where accid=:new.accid;
end if;
end;
insert into trade values(10086,sysdate,'存入',100,null);
创建一触发器,可以有多个动作
craete or replace trigger tr_test
after insert or delete or update on account
for each row
declare
begin
if inserting then
dbms_output.put_line('正在添加的数据:'||:new.accid);
elsif deleting then
dbms_output.put_line('正在添加的数据:'||:old.accid);
elsif updating then
dbms_output.put_line('正在添加的数据:'||:old.accid);
end if;
end;
禁用某个触发器
alter trigger <触发器名> disable
重新启用触发器
禁用所有触发器
数据包
CREATE [OR REPLACE] PACKAGE <数据包名> AS
--公共类型和对象声明
--子程序说明
END;
//创建包
create or replace package mypackage
is
type t_record is record
(
ename varchar2(50),
job varchar2(50),
sal number(10,2)
);
type t_cursor is ref cursor return t_record; --//游标类型
function sum(v_a number,v_b number)return number;
procedure p_getemp(v_deptno in number,v_cursor out t_cursor);
end;
//创建包体实现
create or replace package body mypackage
is
function sum(v_a number,v_b number)return number
is
begin
return v_a+v_b;
end;
procedure p_getemp(v_deptno in number,v_cursor out t_cursor)
is
begin
open v_cursor for select ename,job,sal from emp where deptno=v_deptno;
end;
end;
视图
虚拟的查询
视图本身不保存数据
只支持select
创建视图
create or replacce view v_emp
as
select * from emp;
select * from v_emp;
等价于
select * from
(
select * from emp
);
eg:
create or replacce view v_emp
as
select * from emp
inner join dept on dept.deptno=emp.deptno
inner join salgrade on emp.sal between losal and hisal
–替代触发器–
同义词
create synonym mm for emp;
可以用mm代替emp
索引
加快查询速度(至少40W行数据才有效果)
多用于数据库优化
create index i_1 on emp(empno asc);
正则表达式
regexp_like ‘’
select * from emp where regexp_like(ename ,’\d{1,10}’);
最少出现一个,中间一段最多出现10个,\d数字
异常处理
exception
when <> then
动态执行sql语句
declare
v_sql varchar2(100);
v_ename varchar2(50);
begin
v_sql:='select ename from emp where empno=7788';
execute immediate v_sql into v_ename;
dbms_output.put_line(' ');
end;