oracle个人学习笔记

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_17522211/article/details/84580096
1>-----------------------------表空间-------------------------
1.1>创建表空间example
create tablespace 表空间名称[example]
logging  
datafile 数据库存储位置['/opt/oracle/oradata/orcl/EPSSITE.dbf'] 
size 50m  [初始大小]
autoextend on  
next 50m maxsize 20480m  [每次增长,和最大占有]  
extent management local;
1.2>查看创建好的表空间
select default_tablespace, temporary_tablespace, d.username from dba_users d;

2>------------------------------用户-------------------------------
2.1>创建用户easysite并赋权
create user [用户名称]easysite identified by [密码]easysite default tablespace [表空间]example;
grant connect,imp_full_database,resource,dba[高级权限] to [给用户赋权]easysite;
2.2>查看数据库用户
select  * from dba_users;
2.3>删除用户
drop user 用户名 cascade;---cascade 级联
2.4>----------------------------权限---------------------
2.4.1>-- 用户权限
-- 分配用户 Sam 创建表,创建序列,创建存储过程和创建视图的权限
grant create table,create sequence,create view,create procedure to [用户]sam
-- 去除用户创建视图的权限
revoke create view from sam;
-- 分配用户 Sam 在表 tt 上的 select 权限
grant select on tt to sam;
-- 去除用户 Sam 在表 tt 上的 select 权限
revoke select on tt from sam;
-- 分配表的 Select 权限给所有用户
grant select on tt to public;
-- 去除表的 Select 权限给所有用户
revoke select on tt from public;
2.4.2>-- 角色权限
-- 分配角色 manager 创建表,创建序列的权限
grant create table,create sequence to manager;
-- 去除角色 manager 创建视图的权限
revoke create table from manager;
-- 分配表的 Update 权限给角色 Manager
grant update on tt to manager;
-- 去除表的 Update 权限给角色 Manager
revoke update on tt from manager;

3>还原数据
imp 用户名[easysite]/密码[easysite] file=数据库文件位置[e:/easysite.dmp] full=y

4>备份数据[d:\oracle 目录需要先创建好]
exp user/password@orcl[实例名] file=[文件路径]d:\oracle\example.tmp log=[日志路径]d:\oracle\example.log  






第一课:客户端
        1. Sql Plus(客户端),命令行直接输入:sqlplus,然后按提示输入用户名(scott ),密码(tiger)。
        2. 从开始程序运行:sqlplus,是图形版的sqlplus.
        3. http://localhost:5560/isqlplus
        
        Toad:管理, PlSql Developer:
-------------------------------------------------------------

第二课:更改用户
        1. sqlplus sys/bjsxt as sysdba
        2. alter user scott account unlock;(解锁)
	
	show user  查看当前用户
	conn scott/tiger 更改用户
--------------------------------------------------------------

第三课:table structure
        
        1. 描述某一张表:desc 表名
        2. select * from 表名
----------------------------------------------------------------

第四课:select 语句:

       1.计算数据可以用空表(dual):比如:select 2*3 from dual(sqlserver不成立) select sysdate from dual 查询当前日期

       2.select ename,sal*12 annual_sal from emp;与select ename,sal*12 "annual sal" from emp;区别,加双引号保持原显示方式包括大小写。如果不加 写成annual sal会出错。而且会都显示为大写。(sql server 加不加双引号都是大小写不变)
       
       3. select ename || "abcd" 如果连接字符串中含有单引号,用两个单引号代替一个单引号。(相当于sql server的+)  如果两个单引号是ename'abcd' 如果是单引号是enameabcd
------------------------------------------------------------------------------------------

第五课:distinct
        select deptno from emp;
        select distinct deptno from emp;

        select distinct deptno from emp;
        select distinct deptno ,job from emp
        去掉deptno,job两者组合的重复。更多的项,就是这么多项的组合的不重复组合。
--------------------------------------------------------------------------------------

第六课:Where
        select * from emp where deptno =10;
        select * from emp where deptno <>10;不等于10        
        select * from emp where ename ='bike';
        select ename,sal from emp where sal between 800 and 1500 (>=800 and <=1500)
        空值处理:
        select ename,sal,comm from emp where comm is (not) null;
        select ename,sal,comm from emp where ename ( not)in ('smith','king','abc');
        select ename from emp where ename like '_A%';_代表一个字母,%代表0个或多个字母. 如果查询%,+代表一个或者多个
        可用转义字符.\%. 还可以用escape '$'比如:select ename from emp where ename like '%$a%' escape '$';select ename from emp where ename like '\%a%'
----------------------------------------------------------------------------------------

第七课: orderby
        
         select * from dept; 
         select * from dept order by dept desc;(默认:asc)
         select ename,sal,deptno from emp order by deptno asc,ename desc;
----------------------------------------------------------------------------------------

第八课: sql function1:    
        select ename,sal*12 annual_sal from emp
        where ename not like '_A%' and sal>800
        order by sal desc;

        select lower(ename) from emp;

        select ename from emp 
        where lower(ename) like '_a%';等同于
        select ename from emp where ename like '_a%' or ename like '_A%';

        select substr(ename,2,3) from emp;从第二字符截,一共截三个字符.
        select chr(65) from dual 结果为:A
        select ascii('a') from dual 结果为:65
        select round(23.652,1) from dual; 结果为: 23.7
        select round(23.652,-1) from dual; 20
  
        select to_char(sal,'$99_999_999') from emp;
        select to_char(sal,'L99_999_999') from emp;人民币符号,L:代表本地符号

        这个需要掌握牢:
        select birthdate from emp;
        显示为:
        BIRTHDATE
        ----------------
        17-12月-80
        ----------------

        改为:
        select to_char(birthdate,'YYYY-MM-DD HH:MI:SS') from emp;
        
        显示:
         
        BIRTHDATE
        -------------------
        1980-12-17 12:00:00
        -------------------
        
        select to_char(sysdate,'YYYY-MM-DD HH24:MI:SS') from dual; //也可以改为:HH12
        TO_CHAR(SYSDATE,'YY
        -------------------
        2007-02-25 14:46:14
        

        to_date函数:
        select ename,birthdate from emp where birthdate > to_date('1981-2-20 12:34:56','YYYY-MM-DD HH24:MI:SS');
        如果直接写 birthdate>'1981-2-20 12:34:56'会出现格式不匹配,因为表中的格式为: DD-MM月-YY.
  
        
        select sal from emp where sal>888.88 无错.但
        select sal from emp where sal>$1,250,00;
        会出现无效字符错误. 
        改为:
        select sal from emp where sal>to_number('$1.250.00','$9,999,99');
        
        把空值改为0
        select ename,sal*12+nvl(comm,0) from emp;
        这样可以防止comm为空时,sal*12相加也为空的情况.
------------------------------------------------------------------------------------------

第九课: Group function 组函数
        max,min,avg ,count,sum函数
        
        select to_char(avg(sal),'99999999,99') from emp;
        
        
        select round(avg(sal),2) from emp;
        结果:2073.21
          
        select count(*) from emp where deptno=10;
        select count(ename) from emp where deptno=10; count某个字段,如果这个字段不为空就算一个.
        select count(distinct deptno) from emp;
        select sum(sal) from emp;
------------------------------------------------------------------------------------------

第十课: Group by语句
        
        需求:现在想求,求每个部门的平均薪水.
        select avg(sal) from emp group by deptno;
        select deptno,avg(sal) from emp group by deptno;
        
        select deptno,job,max(sal) from emp group by deptno,job;
        
       求薪水值最高的人的名字.
       select ename,max(sal) from emp;出错,因为max只有一个值,但等于max值的人可能好几个,不能匹配.
       应如下求:
       select ename from emp where sal=(select max(sal) from emp);

       Group by语句应注意,

       出现在select中的字段,如果没出现在组函数中,必须出现在Group by语句中.
-----------------------------------------------------------------------------------------        
    
  第十一课: Having 对分组结果筛选
       
       Where是对单条纪录进行筛选,Having是对分组结果进行筛选.
      
       select avg(sal),deptno from emp 
       group by deptno 
       having avg(sal)>2000;
       
       查询工资大于1200雇员,按部门编号进行分组,分组后平均薪水大于1500,按工薪倒充排列.
       select * from emp 
       where sal>1200
       group by deptno
       having avg(sal)>1500
       order by avg(sal) desc;
------------------------------------------------------------------------------------------
        
   第十二课:子查询
       
       谁挣的钱最多(谁:这个人的名字,  钱最多)
       
       select 语句中嵌套select 语句,可以在where,from后.
       
             
       问那些人工资,在平均工资之上.
       
       select ename,sal from emp where sal>(select avg(sal) from emp);


       查找每个部门挣钱最多的那个人的名字.
       select ename ,deptno from emp where sal in(select max(sal) from ename group by deptno) 查询会多值.

       应该如下:
       
       select  max(sal),deptno from emp group by deptno;当成一个表.语句如下:
       select ename, sal from emp join(select  max(sal) max_sal,deptno from emp group
       by deptno) t on(emp.sal=t.max_sal and emp.deptno=t.deptno); 
       
       每个部门的平均薪水的等级. 
       分析:首先求平均薪水(当成表),把平均薪水和另外一张表连接.
-------------------------------------------------------------------------------------------       
       
第十四课:self_table_connection
       
       把某个人的名字以及他的经理人的名字求出来(经理人及这个人在表中同处一行)
       
       分析:首先求出这个人的名字,取他的编号,然后从另一张表与其相对应编号,然后找到经理的名字.
       
       select e1.ename ,e2.ename from emp e1,emp e2 where e1.mgr= e2.empno.
       
       empno编号和MGR都是编号.
------------------------------------------------------------------------------------------

第十15课: SQL1999_table_connections    
         
      select ename,dname,grade from emp e,dept d, sqlgrade s
      where e.deptno = d.deptno and e.sql between s.losal and s.hisal and
      job<>'CLERK';
      
      有没有办法把过滤条件和连接条件分开来? 出于这样考虑,Sql1999标准推出来了.有许多人用的还是
      旧的语法,所以得看懂这种语句.
      
      
      
      select ename,dname from emp,dept;(旧标准).
      select ename,dname from emp cross join dept;(1999标准)
       
      select ename,dname from emp,dept where emp.deptno=dept.deptno (旧) 
      select ename,dname from emp join dept on(emp.deptno = dept.deptno); 1999标准.没有Where语句.
      select ename,dname from emp join dept using(deptno);等同上句,但不推荐使用.
      
      select ename,grade from emp e join salgrade s on(e.sal between s.losal and s.hisal);
      join 连接语句, on过滤条件。连接,条件一眼分开。如果用Where语句较长时,连接语句和过滤语句混在一起。
      
      三张表连接:
      slect ename,dname, grade from 
      emp e join dept d on(e.deptno=d.deptno)
      join salgrade s on(e.sal between s.losal and s.hisal)
      where ename not like '_A%';
      把每张表连接 条件不混在一起,然后数据过滤条件全部区分开来。读起来更清晰,更容易懂一点。
      
      select e1.ename,e2.ename from emp e1 join emp e2 on(e1.mgr = e2.emptno);

      左外连接:会把左边这张表多余数据显示出来。
      select e1.ename,e2,ename from emp e1 left join emp e2 on(e1.mgr =e2.empno);left 后可加outer
      右外连接:会把右边这张表多余数据显示出来。
    select ename,dname from emp e right outer join dept d on(e.deptno =d.deptno); outer可以取掉。
        
      即把左边多余数据,也把右边多余数据拿出来,全外连接。
      select ename,dname from emp e full join dept d on(e.deptno =d.deptno); 


16-23 课:求部门平均薪水的等级

       A.求部门平均薪水的等级。

       select deptno,avg_sal,grade from 
       (select deptno,avg(sal) avg_sal from emp group by deptno)t
       join salgrade s on(t.avg_sal between s.losal and s.hisal)
       
       B.求部门平均的薪水等级
       select deptno,avg(grade) from 
       (select deptno,ename, grade from emp join salgrade s on(emp.sal between s.losal and
       s.hisal)) t
       group by deptno

       C.那些人是经理
       select ename from emp where empno in(select mgr from emp);
       select ename from emp where empno in(select distinct mgr from emp);
       
       D.不准用组函数,求薪水的最高值(面试题)
       
       select distinct sal from emp where sal not in(
       select distinct e1.sal from emp e1 join emp e2 on (e1.sal<e2.sal));
       
       E.平均薪水最高的部门编号
       
       select deptno,avg_sal from
       (select avg(sal)avg_sal,deptno from emp group by deptno)
       where avg_sal=
       (select max(avg_sal)from 
       (select avg(sal) avg_sal,deptno from emp group by deptno)
       )
      
       F.平均薪水最高的部门名称
       select dname from dept where deptno=
      ( 
        select deptno from
        (select avg(sal)avg_sal,deptno from emp group by deptno)
        where avg_sal=
        (select max(avg_sal)from 
        (select avg(sal) avg_sal,deptno from emp group by deptno)
        )
       )
      
      G.求平均薪水的等级最低的部门的部门名称
        
        组函数嵌套
        如:平均薪水最高的部门编号,可以E.更简单的方法如下:
        select deptno,avg_sal from 
        (select avg(sal) avg_sal,deptno from emp group by deptno)
        where avg_sal =
        (select max(avg(sal)) from emp group by deptno)
        
        组函数最多嵌套两层
        
        分析:
        首先求
        1.平均薪水: select avg(sal) from group by deptno;

        2.平均薪水等级:  把平均薪水当做一张表,需要和另外一张表连接salgrade
        select  deptno,grade avg_sal from 
          ( select deptno,avg(sal) avg_sal from emp group by deptno) t
        join salgrade s on(t.avg_sal between s.losal and s.hisal)
        
        上面结果又可当成一张表。
        
        DEPTNO    GRADE    AVG_SAL
      --------  -------  ----------
        30           3   1566.66667
        20           4   2175
        10           4   2916.66667

        3.求上表平均等级最低值
        
        select min(grade) from
        (
          select deptno,grade,avg_sal from
           (select deptno,avg(sal) avg_sal from emp group by deptno)t
          join salgrade s on(t.avg_sal between s.losal and s.hisa)
         )

        4.把最低值对应的2结果的那张表的对应那张表的deptno, 然后把2对应的表和另外一张表做连接。
          
          select dname ,deptno,grade,avg_sal from
            (
  	      select deptno,grade,avg_sal from
              (select deptno,avg(sal) avg_sal from emp group by deptno)t
             join salgrade s on(t.avg_sal between s.losal and s.hisal)
             ) t1
            join dept on (t1.deptno = dept.deptno)
            where t1.grade =
            ( 
              select deptno,grade,avg_sal from
               (select deptno,avg(sal) avg_sal from emp group by deptno) t
                join salgrade s on(t.avg_sal between s.losal and s.hisal)
               )
            )
         结果如下:
         
        DNAME    DEPTNO     GRADE    AVG_SAL
      --------  -------  --------   --------
        SALES        30        3    1566.6667 
     
         
       H: 视图(视图就是一张表,一个子查询)
        
       G中语句有重复,可以用视图来简化。
       给scott赋视图权限
       conn sys/bjsxt as sysdba;
       grant create table,create view to scott;
       conn scott/tiger
       创建视图:
       create view v$_dept_avg-sal_info as
       select deptno,grade,avg_sal from
        ( select deptno,avg(sal) avg_sal from emp group by deptno)t
       join salgrade s on 9t.avg_sal between s.losal and s.hisal)
      
       然后 
       select * from v$_dept_avg-sal_info
       
       结果如下:
       DEPTNO      GRADE    AVG_SAL
      --------  -------  ----------
        30           3   1566.66667
        20           4   2175
        10           4   2916.66667

       然后G中查询可以简化成:
       select  dname,t1.deptno,grade,avg_sal from
       v$_dept_avg-sal_info t1
       join dept on9t1.deptno =dept.deptno)
       where t1.grade=
       (
	select min(grade) from v$_dept_avg-sal_info t1
       ) 
---------------------------------------------------------------------------------------

第28-29课:创建表: 
constraint:后面添加约束
写字段后面属于字段约束  如名字和邮箱组合不能重复做不到
create table stu
(
id number(6) primary key, 主键约束  不能为空值
name varchar2(20) constraint stu_name_nn not null,  非空约束
sex number(1),
age number(3),
sdate date,
grade number(2) default 1,
class number(4) references class(id),外键约束
email varchar2(50) unique    唯一约束 但是插入空值没问题
)
或者
email varchar2(50) unique,
constraint stu_id_pk primary key(id), 主键约束
constraint stu_class_fk foreign key(本表字段名) references 外表名(外表字段名), 外键约束
constraint stu_name_email_uni unique(email,name)  表级约束 唯一约束
------------------------------------------------------------------------------------------

第30课: 修改表结构
alter table stu add(addr varchar2(100));  添加字段
alter table stu modify(addr varchar2(150)); 修改字段
alter table stu drop(addr); 删除字段
alter table drop constraint(stu_class_fk); 删除约束条件
rollback; 数据恢复
alter table stu add constraint stu_class_fk foreign key(本表字段名) references class(id); 添加新的外键
drop table stu; 删除表
------------------------------------------------------------------------------------------

第32课:  数据字典表
desc user_tables; 查询用户下的表的字段
select table_name from user_tables; 查询表名
select view_name from user_views; 查询视图
select constraint_name,table_name from user_constraints; 查询约束
desc user_constraints;  约束描述查询
desc dictionary;  数据字典的名字和描述
select table_name from dictionary; 查询所有数据字典表
------------------------------------------------------------------------------------------

第33课:索引  视图
--------------------------------------------------------------------------------------
索引
create index idx_stu_email on stu(email,class)/stu(email); 创建索引(通过索引字段去查询,会效率高,但是插入修改时效率不高,反而会低)
drop index idx_stu_email; 删除索引
select index_name from user_indexes; 查询索引
加主键或者唯一约束  会自动建立出索引  如果是字段组合 会自动建立出组合索引
-------------------------------------------------------------------------------------
视图
select view_name from user_views; 查询视图
给scott赋视图创建权限
       conn sys/bjsxt as sysdba;
       grant create table,create view to scott;
       conn scott/tiger
       创建视图:
       create view v$_dept_avg-sal_info as
       select deptno,grade,avg_sal from
        ( select deptno,avg(sal) avg_sal from emp group by deptno)t
       join salgrade s on 9t.avg_sal between s.losal and s.hisal)
      
       然后 
       select * from v$_dept_avg-sal_info

       drop view v$_dept_avg-sal_info; 删除视图

缺点: 如果表结构改了  视图也要修改  增加了维护
功能: 1 简化查询  2 查询某些信息(安全性)
必须有用的时候再去创建视图  视图一般只负责查询 
---------------------------------------------------------------------------------------

第34课:自增
create sequence seq; 创建序列
select sequence seq; 查询序列
select seq.nextval from dual;
insert into article values(seq.nextval,'1','2');
drop sequence seq; 删除序列
---------------------------------------------------------------------------------------

第35课:三范式(实际问题实际分析)
1. 表要有主键  
   列不可分,也不能重复  如姓名 不需要分成姓和名   也不要将姓名和年龄组合为一个列   还有 比如有出生年月不需要再写年龄列 如果写了 就属于重复了
2. 不能存在部分依赖  比如 主键是学号和图书编号组合(2个以上) 那么姓名依赖与学号  那么就属于部分依赖
解决方法 建立第三张表 存学号和图书编号 但是不保存姓名图书名称等信息
3. 不能存在传递依赖 也就是 除主键以外其它字段全部依赖于主键
----------------------------------------------------------------------------------------

第38--46课:PLSQL
1. begin
	dbms_output.put_line('HelloWorld!');  相当于system.out.print();
   end; 不打印
   创建
   set serveroutput on;  想打印要先启用
   begin
	dbms_output.put_line('HelloWorld!');  相当于system.out.print();
   end;
2. declare  定义变量
 declare
	v_name varchar2(20);  变量名用v_开头
  begin
	v_name := 'myname';
	dbms_output.put_line(v_name);
  end;
-----------------------------------------
  declare
	v_num number := 0;  变量名用v_开头
  begin
	v_num := 2/v_num;
	dbms_output.put_line(v_num);
  exception              异常处理
	when others then
	   dbms_output.put_line('error');
  end;

3.变量声明
  declare 
	v_temp number(1);
	v_count binary_integer := 0;
	v_sal number(7,2) := 4000.00;
	v_date date := sysdate;
	v_pi constant number(3,2) := 3.14;  constant 相当于 final 常量
	v_valid boolean := false;
	v_name varchar2(20) not null := 'MyName';  不能取空值
  begin
	dbms_output.put_line('v_temp value:' || v_temp);  || 字符串连接符
  end;
dbms_output.put_line 不能打印boolean值  如果想判断用if else

---变量声明的规则
1. 变量名不能够使用保留字,如from  select 等
2. 第一个字符必须是字母
3. 变量名最多包含30个字符
4. 不要与数据库的表或者列同名
5. 每一行只能声明一个变量

---常用变量类型
1. binary_integer: 整数,主要用来计数而不是用来表示字段类型
2. number:数字类型
3. char:定长字符串
4. varchar2:变长字符串
5. date:日期
6. long:长字符串,最长2GB
7. boolean:布尔类型,可以取值为true flase和null值(建议给个值 不要用Null)

---假如声明变量v_empno number(7,2) 如果表中修改了 那么声明也需要修改 如果想让声明的根据表中的自动修改 用如下命令:
---变量声明,使用%type属性
  declare
	v_empno number(4);
	   v_empno2 emp.empno%type; 1. 表名.字段名%type;
	   v_empno3 v_empno2%type;  2. 变量名%type;
  begin
	dbms_output.put_line('Test');
  end;

4. 复合变量(Table变量类型(表示数组)   Record变量类型(类似于java的类))
---Table变量类型
declare
	关键字  类型名字type_table_            类型           由binary_integer作为索引    
	type type_table_emp_empno is table of emp.empno%type index by binary_integer;
	   v_empnos type_table_emp_empno; 声明变量
begin
	v_empnos(0) := 7369;
	v_empnos(2) := 7839;
	v_empnos(-1) := 9999;
	dbms_output.put_line(v_empnos(-1));
end;

---Record变量类型
declare
	type type_record_dept is record
	  (
	     deptno dept.deptno%type,
	     dname dept.dname%type,
	     loc dept.loc%type
	  );
	 v_temp type_record_dept;
begin
	v_temp.deptno := 50;
	v_temp.dname := 'aaa';
	v_temp.loc := 'bj';
	dbms_output.put_line(v_temp.deptno || ' ' || v_temp.dname);
end;

---如果用以上 那么表添加字段 上面需要跟着添加 如何使用表的字段自动创建 如下
---使用%rowtype声明record变量
declare
	v_temp dept%rowtype;
begin
	v_temp.deptno := 50;
	v_temp.dname := '111';
	v_temp.loc := 'bj';
	dbms_output.put_line(v_temp.deptno || ' ' || v_temp.dname);
end;

5.PL SQL中使用sql
--------------------select---------------------
   declare 
	v_ename emp.ename%type;
	v_sal emp.sal%type;
   begin;
	select ename,sal into v_ename,v_sal from emp where empno=7369;
        dbms_output.put_line(v_ename || ' ' || v_sal);
   end;
   在plsql中 如果使用select,必须返回一条记录,并且只能返回一条记录,select里面必须有into

   ---plsql中使用%rowtype
   declare 
	v_emp emp%rowtype;
   begin;
	select * into v_emp from emp where empno=7369;
        dbms_output.put_line(v_emp.ename);
   end;

-------------------insert into-----------------------
   declare
	v_deptno dept.deptno%type := 50;
	v_dname dept.dname%type := 'aaa';
	v_loc dept.loc%type := 'bj';
   begin
	insert into dept2 values(v_deptno,v_dname,v_loc);
	commit;
   end;

------------------update------------------------------
   declare
	v_deptno emp.deptno%type := 50;
	v_count number;
   begin
	update emp set sal = sal/2 where deptno = v_deptno;
	select deptno into v_deptno from emp where empno = 7369;有一条被影响
	select count(*) into v_count from emp; 也是一条记录被影响
	dbms_output.put_line(sql%rowcount || '条记录被影响');查询影响行数 sql为关键字 
	commit;
   end;

6.ddl

   begin
         固定说明马上执行                                  这是两个单引号
	execute immediate 'create table T(nnn varchar2(20) default ''aaa'')';
   end;

------------------------if---------------------------
---取出7369的薪水,如果<1200,则输出'low',如果<2000则输出'middle',否则输出'high'
declare
	v_sal emp.sal%type;
begin
	select sal into v_sal from emp where empno=7369;
	if(v_sal < 1200) then
		dbms_output.put_line('low');
	elsif(v_sal < 2000) then         elsif 要看清。。
		dbms_output.put_line('middle');
	else
		dbms_output.put_line('high');
	end if;
end;

-----------------------循环--------------------------
1. 相当于java do while
declare 
	i binary_integer := 1;
begin
	loop
	   dbms_output.put_line(i);
	   i := i + 1;
 	   exit when(i >= 11);
        end loop;
end;

2. 相当于java while 
declare 
	j binary_integer := 1;
begin
	while j<11 loop
	   dbms_output.put_line(j);
	   j := j + 1;
        end loop;
end;

3.
begin
	for k in 1..10 loop
		dbms_output.put_line(k); 打印1---10
	end loop;
	
	for k int reverse 1..10 loop
		dbms_output.put_line(k);  打印 10---1
	end loop;
end;
--------------------------------

7.错误处理
declare
	v_emp number(4);
begin
	select empno into v_temp from emp where deptno = 10;
exception 
	when too_many_rows then 
		dbms_output.put_line('有太多记录');
	when others then
		dbms_output.put_line('error');
end;

declare
	v_temp number(4);
begin
	select empno into v_temp from emp where empno = 222;
exception
	when no_data_found then
		dbms_output.put_line('没数据');
end;

-----------利用异常表-----------
---创建异常表
create table errorlog
(
	id number primary key,
	errcode number,
	errmsg varchar2(1024),
	errdate date
);
----创建序列
create sequence seq_errorlog_id start with 1 increment by 1;

---异常使用异常表
declare
	v_deptno dept.deptno%type := 10;
	v_errcode number;
	v_errmsg varchar2(1024);
begin
	delete from dept where deptno = v_deptno;
	commit;
exception
	when others then
		rollback;   事务回滚
			v_errcode := SQLCODE;
			v_errmsg := SQLERRM;
			insert into errorlog values(seq_errorlog_id.nextval,v_errcode,v_errmsg,sysdate);
		commit;
end;

----查询异常   异常编号都是负数
select * from errorlog; 
----查询日期
select to_char(errdate,'YYYY-MM-DD HH24:M1:SS') from errorlog;


---------------------------------------游标-----------------------------------------------
----第47--48课
--游标
declare 
	cursor c is 
		select * from emp;
	v_emp c%rowtype;
begin
	open c;
	fetch c into v_emp;
	dbms_output.put_line(v_emp.ename);
	close c;
end;

---loop循环
declare 
	cursor c is
		select * from emp;
	v_emp c%rowtype;
begin
	open c;
	loop
		fetch c into v_emp;
		exit when (c%notfound);
		dbms_output.put_line(v_emp.ename);
	end loop;
	close c;
end;

---while循环
declare
	cursor c is 
		select * from emp;
	v_emp emp%rowtype;
begin
	open c;
	fetch c into v_emp;
	while(c%fond) loop
		dbms_output.put_line(v_emp.ename);
		fetch c into v_emp;
	end loop;
	close c;
end;

--for循环
declare
	cursor c is 
		select * from emp;
begin
	for v_emp in c loop
		dbms_output.put_line(v_emp.ename);
	end loop;
end

--带参数的游标
declare 
	cursor c(v_deptno emp.deptno%type, v_job emp.job%type)
	is
		select ename,sal from emp where deptno = v_deptno and job = v_job;
begin
	for v_temp in c(30,'CLERK') loop
		dbms_output.put_line(v_temp.ename);
	end loop;
end;

--可更新的游标
declare 
	cursor c
	is 
		select * from emp2 for update;
begin
	for v_temp in c loop
		if(v_temp.sal < 2000) then
			update emp2 set sal = sal*2 where current of c;
		elsif(v_temp.sal = 5000) then
			delete from emp2 where current of c;
		end if;
	end loop;
	commit;
end;



PL/SQL中用游标查询多条记录 
PL/SQL游标为程序提供了从数据库中选择多行数据,然后对每行数据单独进行处理的方法,它为Oracle提供了一种指示和控制SQL处理的各个阶段的方法。我将认为您已经对PL/SQL有一定的了解。通过本文,您将学会: 

游标的创建 
游标的处理 
定义和使用游标属性 
一、 什么是游标 
	Oracle使用两种游标:显式游标和隐式游标。不管语句返回多少条纪录,PL/SQL为使用的每一条UPDATE、DELETE和INSERT等SQL命令隐式的声明一个游标。(要管理SQL语句的处理,必须隐式的	给它定义一个游标。)用户声明并使用显示游标处理SELECT语句返回的多条记录。显示的定义游标一种结构,它使用户能够为特定的语句指定内存区域,以便以后使用。 

二、 游标的作用 
当PL/SQL游标查询返回多行数据时,这些记录组被称为活动集。Oracle将这种活动集存储在您创建的显示定义的已命名的游标中。Oracle游标是一种用于轻松的处理多行数据的机制,没有游标,Oracle开发人员必须单独地、显式地取回并管理游标查询选择的每一条记录。 
游标的另一项功能事,它包含一个跟踪当前访问的记录的指针,这使您的程序能够一次处理多条记录。 

三、 使用显示游标的基本方法 
步骤如下: 

声明游标 
打开游标 
从游标中取回数据 
关闭游标 
1、声明游标 
声明游标的语法如下: 
DECLARE cursor_name 
Is 
SELECT statement 

其中,cursor_name是您给游标指定的名称;SELECT statement是给游标活动集返回记录的查询。 
声明游标完成了下面两个目的: 
给游标命名; 
将一个查询与游标关联起来。 
值得注意的是,必须在PL/SQL块的声明部分声明游标;给游标指定的名称是一个未声明的标识符,而不是一个PL/SQL变量,不能给游标名称赋值,也不能将它用在表达式中。PL/SQL块使用这个名称来引用游标查询。 
例:DECLARE 
CURSOR c1 
Is 
SELECT VIEW_NAME FROM ALL_VIEWS 
WHERE ROWNUM<=10; 
另外还可以在游标定义语句中声明游标的参数,例: 
CURSOR c1(view _nbr number) 
Is 
SELECT VIEW_NAME FROM ALL_VIEWS 
WHERE ROWNUM<= view _nbr; 

游标参数只对相应的游标是可见的,不能在游标范围之外引用该游标的参数。如果试图这样做,Oracle将返回一个错误,指出该变量没有定义。 
2、打开游标 
打开游标的语法如下: 
OPEN cursor_name; 

其中cursor_name是您以前定义的游标名称。 
打开游标将激活查询并识别活动集,可是在执行游标取回命令之前,并没有真正取回记录。OPEN命令还初始化了游标指针,使其指向活动集的第一条记录。游标被打开后,直到关闭之前,取回到活动集的所有数据都是静态的,换句话说,游标忽略所有在游标打开之后,对数据执行的SQL DML命令(INSERT、UPDATE、DELETE和SELECT)。因此只有在需要时才打开它,要刷新活动集,只需关闭并重新打开游标即可。 
3、从游标中取回数据 
FETCH命令以每次一条记录的方式取回活动集中的记录。通常将FETCH命令和某种迭代处理结合起来使用,在迭代处理中,FETCH命令每执行一次,游标前进到活动集的下一条记录。 
FETCH命令的语法: 
FETCH cursor_name INTO record_list; 

其中,cursor_name是前面定义的游标的名称;record_list是变量列表,它接受活动集中的列。FETCH命令将活动集的结果放置到这些变量中。 
执行FETCH命令后,活动集中的结果被取回到PL/SQL变量中,以便在PL/SQL块中使用。每取回一条记录,游标的指针就移向活动集的下一条记录。 
例: 
FETCH C1 INTO VNAME; 
WHILE C1%FOUND LOOP 
DBMS_OUTPUT.PUT_LINE(TO_CHAR(C1%ROWCOUNT)||' '||VNAME); 
END LOOP; 
其中,使用属性'%FOUND'使得当FETCH到达活动集的结尾时,不会引发异常。其它属性及含义见下表: 
属性 含量 
%FOUND 布尔型属性,当最近一次该记录时成功返回,则值为TRUE 
%NOTFOUND 布尔型属性,它的值总与%FOUND属性的值相反 
%ISOPEN 布尔型属性,当游标是打开时返回TRUE 
%ROWCOUNT 数字型属性,返回已从游标中读取的记录数 


属性 含量 
%FOUND 布尔型属性,当最近一次该记录时成功返回,则值为TRUE 
%NOTFOUND 布尔型属性,它的值总与%FOUND属性的值相反 
%ISOPEN 布尔型属性,当游标是打开时返回TRUE 
%ROWCOUNT 数字型属性,返回已从游标中读取的记录数 

4、关闭游标 
CLOSE语句关闭以前打开的游标,使得活动集不确定。当用户的程序或会话结束时,Oracle隐式关闭游标。游标被关闭后,就不能对它执行任何操作了,否则将引发异常。 
CLOSE语句的语法是: 
CLOSE cursor_name; 
其中,cursor_name是以前打开的游标的名称。 
完整的程序代码如下: 
DECLARE 
CURSOR C1 IS SELECT VIEW_NAME FROM ALL_VIEWS 
WHERE ROWNUM<=10 
ORDER BY VIEW_NAME; 
VNAME VARCHAR2(40); 
BEGIN 
OPEN C1; 
FETCH C1 INTO VNAME; 
WHILE C1%FOUND LOOP 
DBMS_OUTPUT.PUT_LINE(TO_CHAR(C1%ROWCOUNT)||''||VNAME); 
END LOOP; 
END; 
……CLOSE C1; 

四、 小结 
游标是一种结构,能够以一次一条记录的方式处理多行查询的结果.为每条DML语句创建隐式游标,而显式游标是由用户创建的,以便处理返回多条记录的查询。而且,通过消除反复地分析代码,游标提高了代码的处理速度。


------------------------------存储过程---------------------------------
---第49--50课
--创建存储过程 执行如果有错误会提示 创建的存储过程带有编译错误 但是不提示哪有错误 
如果想查看 执行show error即可

create or replace procedure p   ---这里相当于declare  
is
	cursor c
	is 
		select * from emp2 for update;
begin
	for v_temp in c loop
		if(v_temp.sal < 2000) then
			update emp2 set sal = sal*2 where current of c;
		elsif(v_temp.sal = 5000) then
			delete from emp2 where current of c;
		end if;
	end loop;
	commit;
end;

select * from emp2;

---执行存储过程
begin 
  p;
end;

exec p; ---执行存储过程

---带参数的存储过程
---创建存储过程
create or replace procedure p
    (v_a in number, v_b number, v_ret out number, v_temp in out number)
---第一个为传入参数  第三个为传出参数  第四个为传入传出参数 
is

begin
    if(v_a>v_b) then
	v_ret := v_a;
    else 
	v_ret := v_b;
    end if;
    v_temp := v_temp + 1;
end;

--定义变量
declare
    v_a number := 3;
    v_b number := 4;
    v_ret number;
    v_temp number := 5;
---执行存储过程
begin
    p(v_a,v_b,v_ret,v_temp);
    dbms_output.put_line(v_ret);
    dbms_output.put_line(v_temp);

--函数
---创建函数
create or replace function sal_tax
	(v_sal number)
	return number
is 
begin
	if(v_sal < 2000) then
		return 0.10;
	elsif(v_sal < 2750) then
		return 0.15;
	else
		return 0.20;
	end if;
end;
--执行函数
select sal_tax(sal) from emp;

----------------------触发器----------------
create table emp2)log
(
uname varchar2(20),
action varchar2(10),
atime date
);
---创建触发器
create or replace trigger trig
    after insert or delete or update on emp2 for each row
begin
    if inserting then
	insert into emp2_log values(USER,'insert',sysdate);
    elsif updating then
	insert into emp2_log values(USER,'update',sysdate);
    elsif deleting then
	insert into emp2_log values(USER,'delete',sysdate);
    end if;
end;

---删除触发器
drop trigger trig;

create or replace trigger trig
   after update on dept
   for each row
begin
    update emp set deptno = :NEW.deptno where deptno = :OLD.deptno;
	
end;

--有了这个触发器  就可以执行 update emp set deptno=10 where deptno=99;  先出发触发器才检查约束条件

select * from emp;

rollback;


------------树状结构展示------------
---第52---53课
drop table article;

create table article
(
id number primary key,
cont varchar2(4000),
pid number,
isleaf number(1),--0代表非叶子节点,1代表叶子节点
alevel number(2)
);

insert into article values(1,'蚂蚁大战大象',0,0,0);
insert into article values(2,'大象被打趴下了',1,0,1);
insert into article values(3,'蚂蚁也不好过',2,1,2);
insert into article values(4,'瞎说',2,0,2);
insert into article values(5,'没有瞎说',4,1,3);
insert into article values(6,'怎么可能',1,0,1);
insert into article values(7,'怎么没有可能',6,1,2);
insert into article values(8,'可能性是很大的',6,1,2);
insert into article values(9,'大象进医院了',2,0,2);
insert into article values(10,'护士是蚂蚁',9,1,3);
commit;

蚂蚁大战大象
	大象被打趴下了
		蚂蚁也不好过
		瞎说
			没有瞎说
		大象进医院了
			护士是蚂蚁
	怎么可能
		怎么没有可能
		可能性是很大的

----------------使用存储过程展示树状结构-------------
create or replace procedure p (v_pid article.pid%type) is
  cursor c is select * from article where pid = v_pid;
begin
  for v_article in c loop
    dbms_output.put_line(v_article.cont);
    if(v_article.isleaf = 0) then
	p (v_article.id);
    end if;
  end loop;
end;
---以上写法 顺序会输出正确 但是没有缩进

create or replace procedure p (v_pid article.pid%type, v_level binary_integer) is
  cursor c is select * from article where pid = v_pid;
  v_preStr varchar2(1024) := '';
begin
  for i in 1..v_level loop
    v_preStr := v_preStr || '*****';  ----如果使用空格 貌似会自动消除
  end loop;

  for v_article in c loop
    dbms_output.put_line(v_preStr || v_article.cont);
    if(v_article.isleaf = 0) then
	p (v_article.id, v_level + 1);
    end if;
  end loop;
end;
---以上写法可以实现缩进

猜你喜欢

转载自blog.csdn.net/qq_17522211/article/details/84580096