oracle小结

数据字典

select * from dba_data_files ;--数据文件。一般来说和表空间是绑定的。
select * from v$controlfile;--控制文件
select * from v$logfile;--日志文件


--常用数据字典

 select * from dba_tablespaces;--全部的表空间
 select * from user_tablespaces;--由于system具有最高权限,查看的也是全部表空间
 
 select count(1) from dba_objects; --查看所有的逻辑对象【所有用户的+sys用户的】
 -- sysdba【sys用户】 > dba【system用户】 >普通用户【其他用户名】
 select count(1) from all_objects; --查询本人权限下能看的所有逻辑对象及公有对象,不包含sys用户创建的非公有。
 select count(1) from user_objects;--本人私有的【创建】逻辑对象

select * from user_role_privs;  --查看当前用户角色

 select * from dba_users;  --查询所有的用户
select * from user_users;  --查询当前用户信息
select * from user_objects;
 select * from all_objects where OWNER='SCOTT';  --相当于上一句
 select * from all_objects where OWNER='SYSTEM'    --SYS,SYSTEM,public,scott
 
alter user scott account unlock  --激活账号
alter user scott identified by orcl123456 --修改密码


create user testuser identified by orcl123456 --创建普通用户
grant resource,connect to testuser; --赋予它登录,和操作常用逻辑对象的权限

create table  test_t(
  id number primary key,
  name varchar2(20) not null
);

--默认开启事务,即不开启自动提交
insert into  testuser.test_t values('1','老白');
insert into  testuser.test_t values('2','小白');


 --查询所有的表
 select * from dba_tables;-- 所有的表,包含公有及sys全部表
 select * from all_tables; --权限范围内的表,包含sys公有表
 select * from user_tables; --私有的表
 
 
 --查询所有权限下能看的视图 ???
 select * from all_views;
 
  --查询所有权限下能看的存储过程 ???
 select * from all_procedures;
 
  --查看运行时数据V$xxx
 select * from v$session;--连接状态
 select * from v$instance;--本实例状态

 
 

索引

--给dept表的depname字段建立唯一索引
create unique index INX_DEPNAME on dept(dname);

--该索引实现dname的唯一约束

insert into depet value('50','RESEARCH','CHINA NANCHANG');--违反唯一约束,无法添加

--删除索引
drop index INX_DEPNAME;

--手动重建索引
alter index INX_DEPNAME rebuild;

--只有deptno索引生效
select * from dept where deptno>'20';
--只有INX_DEPNAME索引生效
select * from dept where dname like 'S%';
select * from dept where dname like '%S';--左模糊查询,索引失效(未证明)

select /*+index(dept INX_DEPNAME)*/
 * from dept where deptno>'20' and dname like 'S%';

同义词

同义词:对“表对象”取同义词,更容易被理解及调用
私有同义词:
create synonym 同义词名 for 表对象

公有同义词:
create public synonym 同义词名 for 表对象


system登录,给testuser用户分配创建同义词的权限

grant create synonym to testuser;  --私有同义词权限

grant create public synonym to testuser;   --公有同义词权限

--testuser登录
select * from scott.emp;
--创建私有同义词
create synonym myemp for scott.emp;

--使用私有同义词
select * from myemp;

--创建公有同义词
create public  synonym pub_scott_emp for scott.emp;

select * from pub_scott_emp   --使用公有同义词

序列

oracle使用序列实现自增或自减。

create sequence 序列名
start with 起点 increment by 步长
[maxvalue 5000]|[nomaxvalue] cycle

--创建序列  从1-10.每次增长1 ,到10以后回到1.缓存5个。

create sequence  myse 
start with 1 maxvalue 10 increment by 1 
cache 5 cycle 。

select  myse.nextval from dual; --获得序列的下一个值
select  myse.currval from dual; --获得序列的当前值
select  myse.nextval,myse.nextval from dual; --一条select语句只能走1步。

create sequence myse2
start with 100  minvalue 0 maxvalue 100 increment by -10
cache 5 cycle

select myse2.nextval from dual; --dual是虚拟表,只是为了sql语句的结构的完整

select sysdate from dual; --当前时间

--通过序列实现记录的插入时自增
create table test_t(
   id number primary key,
   name varchar2(20) not null
)

create sequence  mytestse 
start with 1 nomaxvalue increment by 1 
cache 20 

--使用序列进行主键插入
insert into test_t values(mytestse.nextval,'姓名'||mytestse.nextval);


用户管理

--创建表空间 ,给bai用户专用
create tablespace bai_ts  
datafile 'c:\bai.dbf' size 10M

  --增加容量
alter tablespace bai_ts 
add datafile 'c:\bai2.dbf' size 5M

--创建用户白,绑定上面的表空间
create user bai identified by orcl123456 
default tablespace bai_ts
temporary tablespace temp;

--  授予两个基本角色才能登录。
grant connect,resource to bai;

select * from dba_users where USERNAME='BAI'

select * from dba_tablespaces where tablespace_name='BAI_TS' --查询表空间信息
select * from v$datafile
select * from dba_data_files where tablespace_name='BAI_TS'  --查询表空间对应的数据文件

--修改用户信息
--禁用账号

 alter user bai account lock
 alter user bai account unlock
 
 
 
--- 查看本用户的角色
select * from  user_role_privs;

--查看其他用户的角色
select * from dba_role_privs where grantee='BAI'

--查看指定角色的行为权限
select  * from role_sys_privs  where role='DBA' --
--需要用sysdb身份登录才能看到
select  * from role_sys_privs  where role='RESOURCE' --
select  * from role_sys_privs  where role='CONNECT'


select * from user_role_privs; --查看本用户具有的角色
select * from user_sys_privs;--查看本用户的行为权限。
select * from user_tab_privs;   --查看本用户的表对象权限。

select * from testuser.test_t;



-- 使用system登录,授予testuser 创建视图权限
grant create view to testuser;

--testuser登录,创建视图
create or replace view test_t_count_views 
as select count(1) 记录数 from test_t

select * from testuser.test_t_count_views;


-- testuser登录,无法查询非系统,非公有的私人表
select * from scott.emp;  --失败
-- scott登录,将 emp表的查询和删除权限赋给testuser;
grant select,delete on emp to testuser
-- testuser登录,再次查询emp表
select * from scott.emp;
--删除。允许
delete from scott.emp where empno='7888'
--修改。不允许
update scott.emp set ename = '白' where empno='7888'


--用system登录,创建角色
create role myrole

--让此角色继承两个角色
grant resource,connect to myrole
--让此角色增加 创建视图和创建包的两个系统行为权限
grant create  view to myrole

select * from role_role_privs where role ='MYROLE' --查看角色所继承的角色。

select * from role_sys_privs where role ='MYROLE'  --查看角色所具有的系统行为


--创建新用户  myroleuser 
create user myroleuser  identified by orcl123456

grant myrole to myroleuser;  --赋给它myrole角色。

--使用myroleuser登录
--建表
create table test_t(
   id number primary key,
   rname varchar2(20) not null,
   age number check(age>=0)  --加入check约束,保证参照完整性
)
-- 【resource角色无法完全继承】,还需要system登录后授权
grant resource to myroleuser;

--用myroleuser登录,此时可以操作表了。
insert into test_t values('1','白','2');
insert into test_t values('2','白2','22');

create or replace view  test_t_getname_view
as 
select rname as  姓名 from  test_t;

select * from test_t_getname_view;

create package mypack
as
begin
  
  
end;

内置函数

https://www.cnblogs.com/lukelook/p/11218479.html

--数学类

 select abs(-10) from dual;
 select floor(10.6) from dual;  --往小取整
 select floor(-10.6) from dual;  --往小取整
 select ceil(10.6) from dual; --往大取整
 select ceil(-10.6) from dual; --往大取整
 select round(10.6) from dual; --四舍五入
 select round(-10.6) from dual; --四舍五入
 select sqrt(4) from dual;
 select power(4,2) from dual;
 select power(27,1/3) from dual;
 
 select trunc('1234.5678',3) from dual;--小数点后3位截掉
 select trunc('1234.5678',-2) from dual;--小数点左边第2位开始后面数字用0填充
--123,默认截去小数点后面的部分;
select trunc(123.567) from dual;
 
 
 -- 2 类型转换
  select sysdate from dual;--获得当前的时间日期(datetime类型)
 --转成字符串
 select to_char(sysdate,'yyyy-mm-dd hh24:mi:ss') from dual
 --现在星期几?
 select to_char(sysdate,'day') from dual;
 --显示公元yyyy年 mm月 dd日
 select to_char(sysdate,'"公元"yyyy"年"mm"月"dd"日"') 
 from dual;
 
 --将给定的字符串转成date类型
 select to_date('2013-1-1','yyyy-mm-dd') from dual;
 
 --将字符串进行格式化
  --不满4位用0补齐
 --设计一个方法,使得 学号满足 stu0012。要求引用序列。
 create sequence stu_se ;
 
 drop table student;
 create table student
 (
   stuid varchar2(8) primary key,
   stuname varchar2(256) not null
 )

 insert into student values('stu'||to_char(stu_se.nextval,'0999'),'xxx');

 select * from student;

 select length(to_char('1234','0999')) from dual;
 
-- 3 字符串转换
  select length('abc') from dual;
  select length('a白c') from dual;--字符数
  select instr('abc','xxx') from dual; --起点是1.找不到得到0.
  select trim('  i am a boy! ') from dual;--去头尾
  select replace('  i am a boy! ','boy','girl') from dual;
  select replace('  i am a boy! ',' ','') from dual;
  select * from scott.emp;
  select  empno,ename,job,nvl(comm,'0') from scott.emp;
  select  empno,ename,job,nvl2(comm,'有福利','没福利') from scott.emp;

存储过程

as
 v_ename scott.emp.ename%type;
 v_dname scott.dept.dname%type;
begin
  select scott.emp.ename,scott.dept.dname into v_ename,v_dname from scott.emp, scott.dept 
  where empno=v_empno and scott.emp.deptno = scott.dept.deptno;
  dbms_output.put_line(v_empno||'对应的员工名'||v_ename||',所在部门'||v_dname);
exception
when sys.standard.no_data_found then
  dbms_output.put_line('找不到'||v_empno||'对应的员工');
when others then
  dbms_output.put_line('查找过程出现其他异常!');
end;

--有入参,有出参的情况
create or replace procedure get_add_result(
  i number,j number,v_result out number   --result为出参变量,使用者可以读取
)
as
begin
  v_result := i+j;
end;


--plsql调用含出参的存储过程
declare
 v_result number;  --声明局部变量,作为出参
begin
  get_add_result('10','20',v_result);
  dbms_output.put_line('计算结果:'||v_result);
end;
--有两个出参的存储过程
--有入参,显示表记录的存储。输入工号,显示该工号对应的员工名及部门名
create or replace procedure get_emp_by_eno_proc
(
  v_empno scott.emp.empno%type,  --和emp表的empno字段类型一致
  v_ename out scott.emp.ename%type,
  v_dname out scott.dept.dname%type
)
as

begin
  select scott.emp.ename,scott.dept.dname into v_ename,v_dname from scott.emp, scott.dept 
  where empno=v_empno and scott.emp.deptno = scott.dept.deptno;
exception
when sys.standard.no_data_found then
     v_ename:='查无员工';
when others then
     v_ename:='其他异常';
end;


select * from scott.emp;

函数

--没有入参的函数
create or replace function get_random_func
return number    --返回number类型
as
  v_result number;
begin
    select dbms_random.random into v_result from dual;
    return v_result;
end;


--1个入参的函数,指定返回的随机数 [1,n]
create or replace function get_random_n_func
(n number)
return number    --返回number类型
as
  v_result number;
begin
    if (n<1) then
     dbms_output.put_line('入参非法!');
     return -1; ---1代表入参异常
     end if;
    select mod(abs(dbms_random.random),n)+1 into v_result from dual;
    return v_result;
end;


--找出指定工号的员工的部门所在的位置
create or replace function get_deptloc_by_eno
(v_empno scott.emp.empno%type) return varchar2
as
 v_result scott.dept.loc%type;   --返回值的局部变量
begin
  select scott.dept.loc into v_result  from scott.emp,scott.dept
  where scott.emp.deptno = scott.dept.deptno and scott.emp.empno = v_empno;
  return v_result;
exception
   when no_data_found then
     return '查无'||v_empno||'对应的员工';
   when others then
     return '其他异常';
end;

--找出RESEARCH部门的员工总数


declare
 --v_ename varchar(20);
begin
    update scott.emp set sal = sal*1.2 where empno = '73669';
   --select ename into v_ename from scott.emp where empno='7369';
   dbms_output.put_line('影响行数 :'||sql%rowcount);
end;

select * from scott.salgrade;
grant update on emp to system;

1 编写存储过程 raise_sal_by_eno,给指定工号的员工的薪资提升20%  (commit),提示加薪成功
找不到则控制台输出错误。
create or replace procedure raise_sal_by_eno(v_eno number)
as
begin
  update scott.emp set sal = sal*1.2 where empno = v_eno;
  if (sql%rowcount=1) then
    dbms_output.put_line('提薪成功');
  elsif then
    dbms_output.put_line('提薪失败,'||v_eno||'对应的员工不存在');
   end if;
  commit;
end;

select * from scott.emp where empno='7369'

2 编写函数get_deptempcount_by_eno,返回指定工号的员工的部门的人数。

create or replace function get_deptempcount_by_eno(v_eno number)return number
as
v_result number;
--v_deptno number;
begin
  --select deptno into v_deptno from scott.emp where empno=v_eno;  --先查部门号
  --select count(1) into v_result from scott.emp where deptno = v_deptno; --再查员工人数
  select  count(1) into v_result from scott.emp e1,scott.emp e2 
  where e2.empno='7369' and e1.deptno = e2.deptno;
  return v_result;
  exception 
    when no_data_found then
      dbms_output.put_line('查找失败!');
      return -1;
end;

-- 函数可以一条select中调用
 select get_deptempcount_by_eno('7369')部门人数 from dual;
 
   select  e1.* from scott.emp e1,scott.emp e2 where e2.empno='7369' and e1.deptno = e2.deptno

3 编写函数get_higersal_com,入参为两个员工的工号,获得两个员工中,薪资最高的那个员工的福利 (comm)字段。如果福利为空,则返回0.

create or replace function get_higersal_com
(v_eno1 number,v_eno2 number)
return number
as
 v_sal1 number;
 v_sal2 number;
 v_higher_eno number;--薪资高的员工的工号
 v_comm number; --薪资最高的福利
 v number;
begin
  --各自找出对应的工资
   select sal into v_sal1 from scott.emp where empno = v_eno1;
   select sal into v_sal2 from scott.emp where empno = v_eno2;
   if (v_sal1>v_sal2) then
     v_higher_eno:=v_eno1;
   else
     v_higher_eno:=v_eno2;
     end if;
    select nvl(comm,'0') into v_comm from scott.emp where empno=v_higher_eno;
    return v_comm;
exception
  when no_data_found then
    dbms_output.put_line('查询失败!');
    return -1;
end;


--测试

 select system.get_higersal_com('7369','8888') 高薪员工的福利 from dual


select nvl(comm,'0') from scott.emp where sal =   
 (select max(sal) from scott.emp where empno in('7369','7499')
 )

流程控制



-- plsql语法


--流程控制if的用法
--输入年龄,如果小于12,显示儿童,高于12小于18,显示少年,其它显示成年
declare
  v_age number;
  v_sex varchar(20):='男性';
begin
  v_age:= &你的年龄;
  if (v_age<=12) then
    dbms_output.put_line('儿童');
    if(v_sex='男性') then
       dbms_output.put_line('小男孩');
    end if;
  elsif (v_age>12 and v_age<18) then
    dbms_output.put_line('少年');
  else 
    dbms_output.put_line('成年');
    end if;
end;

--输入一个整数,显示偶数或奇数
--输入一个年,显示平年还是闰年
declare
    n number;
    y number;
begin
    n:=&输入一个整数;
    y:=&输入一个年份;
    if (mod(n,2)=0) then
      dbms_output.put_line(n||'是偶数');
    else
      dbms_output.put_line(n||'是奇数');
    end if;
    
    if (mod(y,4)=0 and mod(y,100)!=0) then
      dbms_output.put_line(y||'是闰年');
    else
      dbms_output.put_line(y||'是平年');
    end if; 
end;


--case
--全条件法
--查询员工的工资等级,
declare
  v_salgrade number; --薪资等级
  v_salary number; --薪资
begin
  v_salary:=&请输入薪资;
  select grade into v_salgrade from scott.salgrade where v_salary between losal and hisal;
  case
     when v_salgrade='1' then 
       dbms_output.put_line(v_salary||'属于最低等级');
     when v_salgrade in (2,3,4) then 
       dbms_output.put_line(v_salary||'属于中等级');
     when v_salgrade='5' then 
       dbms_output.put_line(v_salary||'属于最高等级');
      else  
        dbms_output.put_line(v_salary||'属于其他等级');
    end case;
 exception
    when  no_data_found then
       dbms_output.put_line('找不到'||v_salary||'对应等级');
end;


--等值条件法
declare
v_sleeptime int;
begin
  v_sleeptime:=&请输入睡眠小时;
  case v_sleeptime 
    when '0' then
      dbms_output.put_line('神仙');
    when '1' then
      dbms_output.put_line('半仙');  
    when '2' then
      dbms_output.put_line('偷鸡贼');  
    else
      dbms_output.put_line('普通人');
   end case;
end;

--等值条件法的重要应用

select grade,losal,hisal ,
case to_char(grade) 
  when '1' then '低级 ' 
  when '5' then '高级' 
   else '普通' end as 描述 from scott.salgrade


select * from scott.dept

---  创建视图 emp_dept_info,利用case的转换,显示以下信息   
  工号,员工名,部门名,部门描述(ACCOUNTING-->财务工作,RESEARCH-->研发工作,SALES-->销售工作,PERATIONS-->操作工,其他工作)
 
select scott.emp.empno 工号,scott.emp.ename 员工名,scott.dept.dname 部门名,
case scott.dept.dname 
   when 'ACCOUNTING' then '财务工作'
   when 'RESEARCH' then '研发工作'  
   when 'SALES' then '销售工作'
   when 'OPERATIIONS' then '操作工' end
    as  岗位描述  from scott.emp,scott.dept
     where scott.emp.deptno = scott.dept.deptno



-- for循环,输入n,显示n的斜线
    * 
      * 
        * 
        
 declare
  n number;
  i number;
  j number;
 begin
   n:=&请输入n;
   for i in 1..n loop   --i代表行
       for j in 1..n loop   --j代表列
           dbms_output.put('  ');
           exit when j=i;  -- 相当于  if(xxx) break;
       end loop;
       dbms_output.put_line('*');
   end loop;
   /*
   for i in 1..n loop   --i代表行
       for j in 1..i loop   --j代表列
           dbms_output.put('  ');
       end loop;
       dbms_output.put_line('*');
   end loop;
   */
 end;
 
 
 --- while循环 ,计算1---100之间满足是偶数且整除于7的数的和。
 declare
  i number:=1;
  v_sum number:=0;
 begin
   while(i<=100) loop
      if (mod(i,2)=0 and mod(i,7)=0) then
        v_sum :=v_sum+i;
        end if;
      i:=i+1;
   end loop;
   dbms_output.put_line('结果是:'||v_sum);
 end;
 
 --loop 循环.先执行再判断
 
 declare
 i number:=1;
 v_sum number:=0;
 begin
    loop
      if (mod(i,2)=0 and mod(i,7)=0) then
        v_sum :=v_sum+i;
        end if;
      i:=i+1;
      exit when i=101; --退出的条件
   end loop;
   dbms_output.put_line('结果是:'||v_sum);
 end;
 


游标

https://www.cnblogs.com/guohu/p/11007352.html
https://blog.csdn.net/qq_34745941/article/details/81294166

概念和作用

  • 游标是 sql 的一个内存工作区,由系统或用户以变量的形式定义
  • 游标的作用就是用于临时存储从数据库中提取的数据块(结果集)。
  • 它有一个 指针,从上往下移动(fetch),从而能够遍历每条记录。
  • 牺牲内存 来提升 SQL 执行效率,适用于 大数据处理。
    在这里插入图片描述

游标的属性有四种
在这里插入图片描述
在这里插入图片描述

隐式游标

在这里插入图片描述
例子:

CREATE TABLE stu_info (
  id   NUMBER(3),
  name VARCHAR2(30),
  sex  varchar2(6)
);

-- 增加主键约束
ALTER TABLE stu_info ADD CONSTRAINT pk_stu_info_id PRIMARY KEY (id) ;


-- 插入 2 条测试数据
INSERT INTO stu_info(id, name, sex) VALUES (1, '小游子', '女');
INSERT INTO stu_info(id, name, sex) VALUES (2, '小优子', '男');

COMMIT;

select * from stu_info


begin
   INSERT INTO stu_info (id, NAME, sex) VALUES (3, '瑶瑶', '女');
   IF SQL%FOUND THEN
      dbms_output.put_line('插入成功!');
   END IF;
   end;

显示游标

情况1:不带参数:

DECLARE
   v_stu_info stu_info%ROWTYPE;
   CURSOR cur_stu_info IS
      SELECT * FROM stu_info; -- 步骤1: 声明游标
BEGIN
   OPEN cur_stu_info; -- 步骤2: 打开游标

   -- fetch 一次只能获取一条记录,
   -- 要想获取多条记录可用 循环语句 或者 集合,后面介绍
   FETCH cur_stu_info
      INTO v_stu_info; -- 步骤3: 提取数据

   dbms_output.put_line(v_stu_info.id || ' : ' || v_stu_info.name || ' : ' ||
                        v_stu_info.sex);

   CLOSE cur_stu_info; -- 步骤4: 关闭游标

END;

情况2:带参数(声明参数值和类型):

DECLARE
   v_stu_info stu_info%ROWTYPE;
   CURSOR cur_stu_info(v_id stu_info.id%TYPE) IS
      SELECT * FROM stu_info t WHERE t.id = v_id; -- 步骤1: 声明游标
BEGIN
   OPEN cur_stu_info(1); -- 步骤2: 打开游标

   -- fetch 一次只能获取一条记录,
   -- 要想获取多条记录可用 循环语句 或者 集合,后面介绍
   FETCH cur_stu_info
      INTO v_stu_info; -- 步骤3: 提取数据

   dbms_output.put_line(v_stu_info.id || ' : ' || v_stu_info.name || ' : ' ||
                        v_stu_info.sex);

   CLOSE cur_stu_info; -- 步骤4: 关闭游标

END;

结果:

1 : 小游子 :

动态游标

情况1:弱类型,无 return(常用)

DECLARE
   v_sql  VARCHAR(2000);
   v_b1   NUMBER(3) := 3;
   v_id   system.stu_info.id%TYPE;
   v_name system.stu_info.name%TYPE;
   TYPE cur_stu_type IS REF CURSOR; -- 无 return
   cur_stu_info cur_stu_type;

BEGIN
   v_sql := 'SELECT t.id, t.name 
               FROM stu_info t 
              WHERE t.id <= :b1';

   OPEN cur_stu_info FOR v_sql
      USING v_b1; -- 绑定变量 : 大数据处理常用优化手段

   LOOP
      FETCH cur_stu_info
         INTO v_id, v_name;
      EXIT WHEN cur_stu_info%NOTFOUND;
   
      dbms_output.put_line('序号:' || v_id || chr(10) || '姓名:' || v_name);
   END LOOP;

   CLOSE cur_stu_info;

EXCEPTION
   WHEN OTHERS THEN
      dbms_output.put_line(SQLCODE || ' : ' || SQLERRM);
      dbms_output.put_line(dbms_utility.format_error_backtrace);
END;
select * from dba_objects;

--隐式游标sql

begin
  update scott.emp set sal = sal*1.1 where deptno='10';
  dbms_output.put_line('提取行数:'||sql%rowcount);
  if(sql%isopen) then
    dbms_output.put_line('游标打开');
  else 
    dbms_output.put_line('游标已关闭');
    end if;
   dbms_output.put_line(case (sql%isopen) when true then '打开' else '关闭' end);
end;


-- 显式游标的经典定义
-- 使用游标遍历 scott.emp表
declare
  cursor v_cur 
  is select empno,ename from scott.emp;  -- 1定义一个游标,指向emp表记录集
  v_eno number;--工号
  v_ename varchar2(20); --姓名
begin
  --2 打开游标
   if (not v_cur%isopen) then
     open v_cur;  
     end if;
  --3 提取记录
  loop
     fetch v_cur into v_eno,v_ename ;
     if(v_cur%notfound) then  --已经到达记录的末尾
        exit;
      end if;
     dbms_output.put_line('第'||v_cur%rowcount||'条记录:'||v_eno||','||v_ename);
   end loop;
  --4 关闭游标
   close  v_cur;
end;

-- 带参数的游标

-- -使用游标遍历指定部门编号scott.emp表

declare
  cursor v_cur(v_deptno number) 
  is select empno,ename from scott.emp where deptno=v_deptno;  -- 1定义一个带参数游标,指向emp表记录集
  v_eno number;--工号
  v_ename varchar2(20); --姓名
  v_deptno number;--部门号
begin
  --2 打开游标
  v_deptno:=&请输入员工的部门编号;
   if (not v_cur%isopen) then
     open v_cur(v_deptno);  --打开游标时,传入参数
     end if;
  --3 提取记录
  loop
     fetch v_cur into v_eno,v_ename ;
     if(v_cur%notfound) then  --已经到达记录的末尾
        exit;
      end if;
     dbms_output.put_line(v_deptno||'部门的第'||v_cur%rowcount||'条记录:'||v_eno||','||v_ename);
   end loop;
  --4 关闭游标
   close  v_cur;
end;


--可修改的游标

---修改员工的common字段。如果工资低于2000,则common-200.如果工资高于3000,则common+200.

select * from scott.emp;

declare
 cursor v_cur --定义一个可改游标 
 is 
 select sal,nvl(comm,'0') from scott.emp 
 for update of comm nowait;
   v_sal number;
   v_comm number;
   v_count number:=0;--统计被修改的记录条数
begin
if(not v_cur%isopen) then
         open v_cur;
  end if;
  -- 提取记录
  loop
     fetch v_cur into v_sal,v_comm;
     if(v_cur%notfound) then
       exit;
     else
       case 
         when v_sal<'2000' then
           if(v_comm>200) then
           update scott.emp set comm=v_comm-200 where current of v_cur;
           v_count:=v_count+1;
           end if;
         when v_sal>='3000' then
           update scott.emp set comm=v_comm+200 where current of v_cur;
           v_count:=v_count+1;
         else
           continue;
           end case;
       end if;                 
  end loop;
  dbms_output.put_line('累计有'||v_count||'员工发生改变');  
  close v_cur;  
end;


-- 游标的简化方式1
-- 无需定义 变量来接提取的字段值
--显示部门表的所有信息
select * from scott.dept
declare
  cursor v_cur
  is select * from scott.dept;
begin
   for rec in v_cur loop
     dbms_output.put_line('第'||v_cur%rowcount||'条记录:'||rec.deptno||','||rec.dname||','||rec.loc);
   end loop;
end;


-- 游标的简化方式2
-- 无需定义游标变量
--显示部门表的所有信息

declare
begin
   for rec in (select * from scott.dept) loop
     dbms_output.put_line(rec.deptno||','||rec.dname||','||rec.loc);
   end loop;
end;


--返回游标的函数
--调用者无需关注查询的细节即可遍历数据
-- 返回指向 “入职时间最长的前5个员工信息及它们的入职天数,按倒序排序”的结果的游标
create or replace function get_longesthired_emp
return sys_refcursor
as
   v_cur sys_refcursor; --声明1个未初始化的游标变量
begin
   --前置准备。
  open  v_cur for
   select * from
  (select scott.emp.ename,to_date(sysdate)-hiredate as  入职天数 from scott.emp order by 入职天数 desc
  )where rownum<=5;
  return v_cur;  --返回该游标变量
end;


--调用函数
declare
 v_cur sys_refcursor;
 v_ename varchar2(20);
 v_day number;
begin
  v_cur:=get_longesthired_emp();

  
  loop
    fetch v_cur into v_ename,v_day;
     if(v_cur%notfound) then
       exit;
      end if;
       dbms_output.put_line(v_ename||'入职天数:'||v_day);
  end loop;
  close v_cur;--记得关闭
end;
 /*

   select * from
  (select scott.emp.*,to_date(to_char(sysdate,'yyyy-mm-dd'))-hiredate as  入职天数 from scott.emp order by 入职天数 desc
  )where rownum<=5;
  */



触发器

主键自增例子

--最简单的触发器
drop table test_t;
   create table test_t 
   (
       id number primary key,
       tname varchar(20) not null
   );
   
   insert into test_t values('1','张三');
   insert into test_t values('2','李四');
   commit;
   
 --创建1个insert语句前触发器  
 create or replace trigger test_t_tri
 before insert on test_t
 declare
 begin
   if (to_char(sysdate,'day')='星期五') then
     raise_application_error(-20000,'周四无法插入数据');   --抛异常,取消插入
     end if;
   dbms_output.put_line('插入记录成功-语句前1');
 end;
 
  create or replace trigger test_t_tri2
 before insert on test_t
 declare
 begin
   if (to_char(sysdate,'day')='星期五') then
     raise_application_error(-20000,'周四无法插入数据');   --抛异常,取消插入
     end if;
   dbms_output.put_line('插入记录成功-语句前2');
 end;
 
 insert into test_t values('3','王五');
 insert into test_t values('5','马六');
 
 select * from test_t;
 
 ---行触发器例子1
  ---插入记录的name含有 sb话,自动删除sb 
create  or  replace trigger test_t_checkname_tri
before insert on test_t  for each row  --insert的行前触发器。行触发器中可以读取新插入的字段值  :new
declare
begin
  if instr(:new.tname,'sb')>0 then
    :new.tname := replace(:new.tname,'sb','');
    dbms_output.put_line('发生替换!');
    end if;
end;

insert into test_t values('6','王五');
insert into test_t values('7','basbi');
select * from test_t;

 ---行触发器例子2
 ---添加名字的长度,不能高于现存记录的最高长度,否则禁止修改
 
 select max(length(tname)) from test_t;
 
 create or replace trigger test_t_checkupdatename_tri
 before insert on test_t for each row
 declare
    v_maxlen number;
 begin
    select max(length(tname)) into v_maxlen from test_t;
    if (length(:new.tname)>v_maxlen) then
      raise_application_error(-20000,'长度不能超过'||v_maxlen);
      end if;
     dbms_output.put_line('插入成功');
 end;
 
 insert into test_t values('10','张三糁洒洒你');
 
 --行触发器例子3  

 
 create  table test_t_bk     --只赋值数据和表结构,没有赋值主键约束。
  as (select * from test_t)
  
  select * from test_t_bk;
  truncate table test_t_bk;
   --删除记录的备份。 :old来访问删除前的记录。将删除的每一条记录,都备份到备份表中
  create or replace trigger test_t_deletebk_tri
 after delete on test_t for each row 
 declare
 begin
     insert into test_t_bk values(:old.id,:old.tname);
     dbms_output.put_line('备份:'||:old.id||','||:old.tname);
 end;
 
 
 delete from test_t where id>1
 
--行触发器例子4
--insert 行前触发器,实现免序列引用的主键自增
create sequence myse start with 1 nomaxvalue cache 20;
truncate table test_t;

 insert into test_t values(myse.nextval,'xxx');
 -->简化成
  insert into test_t (tname) values('xxx');
  
--思路 创建行前触发器 before insert on test_t for each row
如果 :new.id 为 空,则将其替换为 myse.nextval的值。
create or replace trigger test_t_autoincrement_tri
before insert on test_t for each row
declare
begin
    if (:new.id is null) then
      select myse.nextval into :new.id  from dual;
    end if;
end;

insert into test_t (tname) values('xx');
insert into test_t  values('10','xx');
insert into test_t  values('15','xx');

insert into test_t  values('23','xx');

select * from test_t;

--如何实现可以设置不冲突主键的触发器

create or replace trigger test_t_autoincrement_tri2
before insert on test_t for each row
declare
 v_maxid number;
 v_nextval number;
begin
    select max(id) into v_maxid from test_t;
    if (:new.id is null) then
      loop
       select myse.nextval into v_nextval from dual;
              exit when v_nextval>v_maxid;  --一直走到当前最大的id
       end loop;
      select myse.currval into :new.id  from dual;
    end if;
end;

create or replace trigger test_t_autoincrement_tri3
before insert on test_t for each row
declare
 v_id number;
 v_nextval number;
begin
    if (:new.id is null) then
      loop
       select myse.nextval into v_nextval from dual;
       select id into v_id from test_t where id=v_nextval;   --找不到则抛异常 
       end loop;
    end if;
 exception 
     when no_data_found then  --说明没有重复,可以使用
        select myse.currval into :new.id  from dual;
end;

insert into test_t (tname) values('xx');

insert into test_t  values('25','xx');

select * from test_t;



例子

create or replace package mycalculator
is
  --声明公有变量
  version varchar2(20):='0.1版';
  --声明公有函数
  function add(i number,j number) return number;
  function sub(i number,j number) return number;
  function multi(i number,j number) return number;
  function divide(i number,j number) return number;
  --声明公有存储过程
  procedure showinfo;
end;


--创建包体
create or replace package body mycalculator
is
  --声明私有变量
  x number:=100;
  --实现公有函数
  function add(i number,j number) return number
  as
  begin
    return i+j;
  end;
  function sub(i number,j number) return number
  as
  begin
    return i-j;
  end;
  function multi(i number,j number) return number
  as
  begin
    return i*j;
  end;

  function divide(i number,j number) return number
  as
   r number;
  begin
   r:= i/j;
   return r;
   exception
   when sys.standard.ZERO_DIVIDE then
    dbms_output.put_line('0不能做除数!');
    return -10000;
  end;
  
   function add_one(x number)  --私有的方法!
  return number
  as
   r number;
  begin
   r:=x+1;
   return r;
  end;
  
  procedure showinfo  --公有的存储过程
  as
  begin    
   dbms_output.put_line('这是要显示的信息!!! x='||x||',addone(x)的结果:'
   ||add_one(x));
  end;

end;

   declare
   v_result number;
   begin
    v_result:= system.mycalculator.add(1,2);
    dbms_output.put_line('result='||v_result);
  dbms_output.put_line('公有变量:'||system.mycalculator.version);
  system.mycalculator.showinfo();  --访问包的公有存储过程
   end;

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

java后端指南

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值