oracle 学习笔记之二

版权声明: https://blog.csdn.net/qq_34475529/article/details/84070330

多表查询:
    内联接
      等值联接
      inner join
    外连接
      left outer join
      right outer join
      Oracle特有的写法(+)
      
    子查询:
--内联接的结果
select * from emp e1,emp t1 where e1.mgr = t1.empno;
--t1表里面的所有记录都会显示出来, 如果t1.empno 在e1.mgr中没有对应的记录,就加空值
select * from emp e1,emp t1 where e1.mgr(+) = t1.empno;
--查询不是领导的员工编号
select empno from emp where empno not in (select mgr from emp where mgr is not null);

--获取员工的名字和部门的名字
select e.ename,d.dname from emp e,dept d where e.deptno = d.deptno;
----使用子查询的方式来完成
select ename,deptno from emp;

select ename,deptno,deptno from emp;
--关联子查询, 子查询依赖外部查询的条件
select e.ename,e.deptno,(select d.dname from dept d where d.deptno = e.deptno ) aa from emp e;


--统计薪资大于薪资最高的员工所在部门的平均工资和薪资最低的员工所在部门的平均工资的平均工资的员工信息。


/*
     Oracle体系结构:
      数据库 ---> 数据库实例ORCL ---> 表空间 (用户里面的创建表) ---> 数据文件 
      地球   ---> 中国           ---> 省份  (人民)              ---> 土地山川河流
     
     雄安新区 ---> 人(开发荒地,种地)
                
     
     创建表空间: 逻辑单位, 通常我们新建一个项目,就会去新建表空间,在表空间中创建用户来创建表
           语法:
               create tablespace 表空间的名称
               datafile '文件的路径(服务器上)'
               size 大小
               autoextend on  自动扩展
               next 每次扩展的大小
*/
--切换到system帐号下创建
--创建一个表空间 --- 汉东
create tablespace handong
datafile 'c:\handong.dbf'
size 100m
autoextend on
next 10m;


--删除表空间
drop tablespace handong;


/*
   创建用户 
     create user 用户名
     identified by 密码
     default tablespace 表空间的名称
*/
create user dakang
identified by dakang
default tablespace handong;

/*
授权   grant 角色 | 权限  to 用户
*/
grant connect to dakang;

--授予 dba的角色
grant dba to dakang;


select * from scott.emp;


/*
      创建表:
         create table 表名(
           列名  列的类型 [列的约束],
           列名  列的类型  [列的约束]      
         );
      列的类型:
         varchar ,在Oracle中,目前是支持的, 但是不保证以后还支持
         
         varchar2(长度) 可变字符长度    varchar2(10)  hello  占5个字符
         char(长度)   固定长度字符      char(10)      hello  占10个字符,用空格填充
         number(总长度,小数长度)     数字类型 --小数长度不能大于等于总长度
         
         date                   年月日时分秒 2017/4/13 9:43:49
         timestamp              时间戳, 比date类型更加精确 13-APR-17 09.44.08.272000 AM +08:00
         
         LONG/CLOB : 存放一本小说
         BLOB      : 存放电影  java 存进去,  再读取出来
     

扫描二维码关注公众号,回复: 5411395 查看本文章

    使用子查询的方式创建表
         
         create table 表名 as 查询语句; 
         
           注意: 只会复制表结构和表中的数据,不会复制列的约束     
                 如果查询语句有结果, 就是复制 表结构和数据
                 如果查询语句没有结果, 就是复制 表结构   
         
*/
create table test1(
   name1 varchar2(10),
   name2 char(10),
   age   number(2,3)    
);

insert into test1(name1,name2) values('hello','hello');

select * from test1 where name1 like 'hello'; --可以查询数据
select * from test1 where name2 like 'hello'; --查不出数据

insert into test1(age) values(2);

select current_date from dual;
select current_timestamp from dual;

select * from test1;

--  create table 表名 as 查询语句; 复制表     
select * from scott.emp;

create table emp as select * from scott.emp;

--如果查询语句是没有任何的结果的
select * from scott.emp where 1=2;
create table emp1 as select * from scott.emp where 1=2;


select * from emp1;


/*
    修改表:
       添加列
       修改列 vharchar2(10)
       删除列
       修改列名
       
       重命名表   
       
  SQL分类:
       DDL : 数据定义语言, 修改的结构  alter create drop truncate
       DML : 数据操纵语言 , 操作表中数据 insert update delete
       DCL : 数据控制语言 , grant     
       DQL : select
*/
create table stu(
    stuid number,
    sname varchar(10)   
);

--添加一列  
alter table stu add phone varchar2(11);

alter table stu add (
                          mobile varchar2(11),
                          sex    varchar2(2)
                     );

--修改列的类型
alter table stu modify sex varchar2(4);

--修改列名 sex --- gender
alter table stu rename column sex to gender;

--删除列
alter table stu drop column gender;

--修改表名
rename stu to student;

--删除表
drop table student;


/*
   表的五大约束
   列的约束: 约束主要是用来约束表中数据的规则
     主键约束: primary key 不能为空, 必须唯一
     非空约束
     唯一约束
     检查约束 check(条件)  在mysql中是可以写的,但是mysql直接忽略了检查约束
     
     外键约束:
          主要是用来约束从表A中的记录,必须是存在于主表B中
*/
--男,女,人妖
create table student(
    stuid number primary key,
    sname varchar2(10) unique,
    age   varchar2(10) not null,
    gender varchar2(4) check( gender in ('男','女','人妖'))
);
--主键约束违反
insert into student values(1,'张三','31','男');
insert into student values(1,'李四','31','男');
--唯一约束违反
insert into student values(1,'徐立','31','男');
insert into student values(2,'徐立','31','男');
--非空约束
insert into student values(1,'徐立',null,'男');
--检查约束
insert into student values(1,'徐立','31','男');

insert into student values(1,'徐立','31','妖');

select * from student;

/*
     商品分类,商品表
     
*/
--商品分类表
create table category(
       cid number primary key,
       cname varchar2(20)
);

--创建一个商品表
create table product(
       pid number primary key,
       pname varchar2(20),
       cno number
);

insert into category values(1,'手机数码');

insert into product values(10,'锤子',11);

--添加外键约束
alter table product add foreign key(cno) references category(cid);
insert into product values(10,'锤子',11);--插入失败

--1.首先主表中必须存在11号, 先往主表中插入数据,再往从表中插入数据
insert into category values(2,'电脑办公');
insert into product values(11,'外星人',2);


--删除Category
drop table category; --表中记录被外键关联无法删除

--强制删除表(不建议使用) : 先删除外键关联表的外键约束,然后再删除自己, 先删除product的外键约束,再删除category
drop table category cascade constraint;


--级联删除
----添加外键约束,使用级联约束  ,在删除的时候,使用级联删除
alter table product add foreign key(cno) references category(cid) on delete cascade;


insert into category values(2,'电脑办公');
insert into product values(11,'外星人',2);

--级联删除 : 首先去从表中找有没有 关联数据, 如果在从表中找到关联数据,先删除从表中关联数据,然后再删除表中的数据
delete from category where cid = 2;


select * from category;
select * from product;

drop table product;
truncate table product;
truncate table category;

/*
     插入数据:
         insert into 表名 values(所有列的值都要对应写上)
         insert into 表名(列1,列2) values(值1,值2);
         
     使用子查询插入数据
         insert into 表名 查询语句
*/
select * from emp1;

select * from emp;
--将emp中10号部门的员工信息,插入到emp1中
insert into emp1 select * from emp where deptno = 10;


/*
     更新数据
       update 表名 set 列名 = 列的值  [where 条件]
*/
update emp1 set ename='HUAAN' where ename = 'KING';
select * from emp1;

/*
     删除数据:
       delete from 表名  [where 条件]
       
       delete和truncate 区别
        
       delete:                 truncate:
        DML                    DDL
        逐条删除               先删除表再创建表
        支持事务操作           不支持事务操作,
                               执行效率要高  
       
       
*/
delete from emp1 where empno=7839;

/*
   事务: 就是一系列的操作,要么都成功,要么都失败
       四大特性: 原子性,隔离性,持久性,一致性
          
       如果不考虑隔离级别: 脏读,虚读,不可重复读
            MYSQL隔离级别: READ UNCOMMITTED , READ COMMITTED, REPEATABLE READ, SERIALIAZABLE
            ORACLE隔离级别: READ COMMITTED SERIALIZABLE READ ONLY 
                        默认隔离级别: READ COMMITTED
                        
      提交 : commit
      事务的保存点/回滚点: savepoint 保存点的名称
      回滚: rollback
*/
create table louti(
   lou number primary key    
);

insert into louti values(1);
insert into louti values(2);
insert into louti values(3);
insert into louti values(4);
insert into louti values(5);
savepoint dangban;
insert into louti values(5); --主键约束会发生异常
insert into louti values(6);
rollback to dangban
commit;


declare

begin
  insert into louti values(1);
  insert into louti values(2);
  insert into louti values(3);
  insert into louti values(4);
  insert into louti values(5);
  savepoint dangban;
  insert into louti values(5);  --这行代码会发生异常
  insert into louti values(6);
  commit;
exception  --捕获异常
  when others then
     rollback to dangban;
     commit;
end;

select * from louti;

/*
      视图: 是对查询结果的一个封装
              视图里面所有的数据,都是来自于它查询的那张表,视图本身不存储任何数据
          1.能够封装复杂的查询结果
          2.屏蔽表中的细节
       语法: 
          create [or replace] view 视图的名称 as 查询语句 [ with read only]
          
       注意: 通常不要通过视图去修改,视图创建的时候,通常要加上with read only
*/
select * from emp;

--创建一个视图
create or replace view view_test1 as select ename,job,mgr from emp;

--通过视图修改数据
update view_test1 set ename='SMITH2' where ename = 'SMITH';

--创建一个只读视图
create or replace view view_test2 as select ename,job,mgr from emp with read only;

update view_test2 set ename='SMITH3' where ename = 'SMITH2';

--视图封装复杂的查询语句
create view view_test3 as select
      sum(cc) "TOTAL",
      sum(case yy when '1980' then cc end) "1980",
      sum(case yy when '1981' then cc end) "1981",
      sum(case yy when '1982' then cc end) "1982",
      sum(case yy when '1987' then cc end) "1987"
from
      (select  to_char(hiredate,'yyyy') yy,count(1) cc from emp group by  to_char(hiredate,'yyyy')) tt;

--同义词的概念
create synonym dept for view_test3;

create synonym yuangong for view_test2;

select * from yuangong;

select * from dept;

select * from view_test3;

select * from view_test2;

/*
    序列: 生成类似于 auto_increment 这种ID自动增长 1,2,3,4,5....
       auto_increment 这个是mysql  
       
       语法:
           create sequence 序列的名称
           start with 从几开始
           increment by 每次增长多少
           maxvalue 最大值 | nomaxvalue
           minvalue 最小值 | nominvalue
           cycle | nocycle  是否循环    1,2,3,1,2,3
           cache 缓存的数量3 | nocache  1,2,3,4,5,6 
           
      如何从序列获取值
          currval : 当前值
          nextval : 下一个值
          
               注意: currval 需要在调用nextval之后才能使用      
               
               永不回头,往下取数据, 无论发生异常, 回滚   
*/
--创建一个 1,3,5,7,9......30 
create sequence seq_test1
start with 1
increment by 2
maxvalue 30
cycle
cache 10;

select seq_test1.nextval from dual;
select seq_test1.currval from dual;

--序列用的最多的一种写法
create sequence seq_test2;
select seq_test2.nextval from dual;


create sequence seq_test3
start with 1
increment by 2
maxvalue 30
minvalue 0
cycle
cache 10;

select seq_test3.nextval from dual;

/*
    索引:相当于是一本书的目录,能够提高我们的查询效率
       如果某一列,你经常用来作为查询条件,那么就有必要创建索引,数据量比较的情况
       
       语法: 
             create index 索引的名称 on 表名(列)   
        
       注意:主键约束自带主键索引, 唯一约束自带唯一索引
       
       索引原理: btree   balance Tree 平衡二叉树
       
             如果某列作为查询条件的时候,可以提高查询效率,但是修改的时候,会变慢
             
             索引创建好之后,过了一段,DBA都会去做重构索引
             
       SQL调优:
             1.查看执行计划F5
             2. 分析里面的cost 和 影响行数, 想办法降低            
*/
--五百万数据测试
create table wubaiwan(
      name varchar2(30),
      address varchar2(20) 
);

insert into wubaiwan values('')

--插入500000万条数据
declare

begin
     for i in 1..5000000 loop
       insert into wubaiwan values('姓名'||i,'地址'||i);
     end loop;
     commit;  
end;

--在没有添加索引的情况下,去查询  name='姓名3000000'  --2.985
select * from wubaiwan where name='姓名3000000';

--创建索引 name 再去查询 name='姓名3000000'
create index ind_wubaiwan on wubaiwan(name);
select * from wubaiwan where name='姓名3000000';  --0.016

--在没有添加复合索引的情况下,再去查询 name='姓名3000000' and '地址3000000'
select * from wubaiwan where name='姓名3000000' and address='地址3000000'; --0.032

--创建复合索引的情况下, 再去查询
create index ind_wubaiwan2 on wubaiwan(name,address);
select * from wubaiwan where name='姓名3000000' and address='地址3000000'; --0.015

/*
     DDL表空间操作
         创建表空间
         创建用户
         授权
         
         创建表
              子查询创建表
         修改表 : 添加列,删除列,修改列,修改列名, 修改表名
         
         约束:
             主键约束,唯一约束,非空约束,检查约束,外键约束
             
             外键约束:
               强制删除
               级联删除
             
     DML表中数据:
         插入数据
             子查询插入数据
         更新数据
         删除数据: delete 和 truncate
         
         事务操作:
               savepoint 保存点
               rollback to 保存点
          ORACLE事务隔离级别  : READ COMMITTED 
          
     视图: 就像窗户一样, 封装查询结果 , 通常视图创建只读视图
     序列: 主要是用来实现ID自增长 
     索引: 相当于是书的目录,能够提高查询效率, 原理 平衡二叉树, 每隔一段时间DBA都需要去重建索引
     同义词: create synonym 名称 for 对象的名称          

*/
/*
     PLSQL编程 : procedure Language 过程语言 Oracle对SQL的一个扩展
             让我们能够像在java中一样写 if else else if 条件, 还可以编写循环逻辑 for while
             
             declare
                --声明变量
                变量名 变量类型;
                变量名 变量类型 := 初始值;
                  vsal emp.sal%type;  --引用型的变量  
                  vrow emp%rowtype;   --声明记录型变量          
             begin
                --业务逻辑
             end;
             
             dbms_output.put_line()相当于java中 syso 
*/
declare
   i varchar2(10) := '张三';          
begin
  dbms_output.put_line(i);
end;

--查询7369的工资,并且打印出来
declare
  vsal emp.sal%type;
begin
  --将查询出的结果赋值给vsal
  select sal into vsal from emp where empno = 7369;
  
  dbms_output.put_line(vsal);
end;

--查询7369的员工信息,并且打印出来
 select * from emp where empno = 7369;

declare
  vrow emp%rowtype;      
begin
  select * into vrow from emp where empno = 7369;
  
  dbms_output.put_line('姓名:'||vrow.ename || '工资'|| vrow.sal);
end;

/*
  PL条件判断
     
     if then
     
     elsif then
       
     else 
     
     end if;
*/
--根据不同年纪,输出相关内容
declare
   age number := &aaa;
begin
  if age < 18 then
     dbms_output.put_line('小屁孩');
  elsif age>=18 and age <=24 then
     dbms_output.put_line('年轻人');
  elsif age>24 and age < 40 then
    dbms_output.put_line('老司机');
  else 
      dbms_output.put_line('老年人');    
  end if;
end;

/*
  循环操作
  while 循环
      while 条件 loop
        
      end loop;
    
  for循环
      for 变量  in [reverse] 起始值..结束值 loop
        
      end loop;
  
  loop循环  
      loop
        exit when 条件
      end loop;
      
*/
--输出1~10
declare
  i number :=1;
begin
  while i<=10 loop
    dbms_output.put_line(i);
    i := i+1;    
  end loop;
end;

--输出1~10
declare

begin
  for i in reverse 1..10 loop
    dbms_output.put_line(i);
  end loop;
end;

--输出1~10
declare
   i number :=1;
begin
   loop
     exit when i>10;
      dbms_output.put_line(i);  
     i := i+1;
   end loop;
end;

/*

   *
  ***
 *****
  ***
   *   
输出 m  
   x : [-m,m]
   y : [-m,m]
   
   输出所有满足条件的 : abs(y)+abs(x) <=m
   
   m取值
*/
--使用PLSQL输出菱形
declare
   m number := 10;
begin
   for x in -m..m loop
     for y in -m..m loop
       if abs(y) + abs(x) <= m then
         dbms_output.put('*');
       else
         dbms_output.put(' ');
       end if;      
     end loop;
     dbms_output.new_line();
   end loop;  
end;

--使用PLSQL输出三角形,只要是三个角
declare
   m number := 10;
begin
   for x in reverse -m..m loop
     for y in -m..m loop
       if abs(y) + abs(x) <= m and x>=0 then
         dbms_output.put('*');
       else
         dbms_output.put(' ');
       end if;      
     end loop;
     dbms_output.new_line();
   end loop;  
end;

/*
  序列: ORACLE使用来模拟ID自动增长的
  
*/
create sequence seq_test4;

create table test2(
   tid number primary key,
   tname varchar2(10)    
);

insert into test2 values(seq_test4.nextval,'张三');
select * from test2;

/*
       PLSQL编程: 过程语言,编写一些复杂业务逻辑  
       
       输出星号:
                abs(y) + abs(x) <= m   
                
       vsal  emp.sal%type --引用型变量
       row  emp%rowtype  --记录型变量
       
       select sal into vsal from emp where empno=7788;
*/
declare
   m number := 3;             
begin
   for y in -m..m loop
     for x in -m..m loop
         if abs(y) + abs(x) <= m then
            dbms_output.put('*');
         else  
            dbms_output.put(' ');  
         end if;
     end loop;
     dbms_output.new_line();
   end loop;  
end;


/*
   游标(光标): 是用来操作查询结果集,相当于是JDBC中ResultSet
       
       语法: cursor 游标名[(参数名 参数类型)] is 查询结果集
       
       开发步骤:
           1. 声明游标
           2. 打开游标       open 游标名
           3. 从游标中取数据  fetch 游标名 into 变量
                         游标名%found :找到数据
                         游标名%notfound : 没有找到数据 
           4. 关闭游标       close 游标名
           
      系统引用游标
           1. 声明游标 : 游标名 sys_refcursor
           2. 打开游标: open 游标名 for 结果集
           3. 从游标中取数据
           4. 关闭游标
                
     for循环遍历游标:
           不需要声明额外变量
           不需要打开游标
           不需要关闭游标      
*/
--输出员工表中所有的员工姓名和工资(不带参数游标)
/*
   游标:所有员工
   声明一个变量,用来记录一行数据  %rowtype
*/
declare
   --游标
   cursor vrows is select * from emp;
   --s声明变量,记录一行数据
   vrow emp%rowtype;
begin
   --1.打开游标  
   open vrows;
   --2.从游标提取数据
   --循环取数据
   loop
       fetch vrows into vrow; 
       exit when vrows%notfound;  
       dbms_output.put_line('姓名:'||vrow.ename ||' 工资: ' || vrow.sal);
   end loop;
   --3.关闭游标
   close vrows;
end;

--输出指定部门下的员工姓名和工资
/*
   游标: 指定部门的所有员工
   声明一个变量记录一行数据
*/
declare
   --声明游标
   cursor vrows(dno number) is select * from emp where deptno = dno;
   --声明变量
   vrow emp%rowtype;
begin
  --1.打开游标 , 指定10号部门
  open vrows(10);
  --2. 循环遍历,取数据
  loop
     fetch vrows into vrow;
     exit when vrows%notfound;    
      dbms_output.put_line('姓名:'||vrow.ename ||' 工资: ' || vrow.sal);
  end loop;
  close vrows;
end;

--系统引用游标
--输出员工表中所有的员工姓名和工资
declare
  --声明系统引用游标
  vrows sys_refcursor;
  --声明一个变量
  vrow emp%rowtype;
begin
  --1.打开游标
  open vrows for select * from emp;
  --2.取数据
  loop
    fetch vrows into vrow;
    exit when vrows%notfound;
     dbms_output.put_line('姓名:'||vrow.ename ||' 工资: ' || vrow.sal);
  end loop;
  close vrows;
end;

--扩展内容----使用for循环遍历游标
declare
  --声明一个游标
  cursor vrows is select * from emp;
begin
  for vrow in vrows loop
     dbms_output.put_line('姓名:'||vrow.ename ||' 工资: ' || vrow.sal || '工作:'|| vrow.job);
  end loop;
end;

select * from emp;

--按照员工工作给所有员工涨工资,总裁涨1000,经理涨800,其他人涨400
/*
    游标 : 所有员工
    声明一个记录一行数据   
*/
declare
   --声明游标
   cursor vrows is select * from emp;
   --声明一个变量
   vrow emp%rowtype; 
begin
  --1.打开游标
  open vrows;
  --2.循环取数据
  loop
       --取数据
       fetch vrows into vrow;
       --退出条件
       exit when vrows%notfound;  
       --根据不同的职位,涨工资 总裁涨1000,经理涨800,其他人涨400
       if vrow.job = 'PRESIDENT' then
          update emp set sal = sal + 1000 where empno = vrow.empno;
       elsif vrow.job = 'MANAGER' then
          update emp set sal = sal + 800 where empno = vrow.empno;
       else
          update emp set sal = sal + 400 where empno = vrow.empno; 
       end if;       
  end loop;
  --3.关闭游标
  close vrows;
  --4.提交事务
  commit;
end;


select * from emp;


/*
   例外:(意外)程序运行的过程发生异常,相当于是JAVA中的异常
   
   declare
       --声明变量
   begin
       --业务逻辑
   exception
       --处理异常
       when 异常1 then
         ...
       when 异常2 then
         ...
       when others then
         ...处理其它异常
   end;
   
   zero_divide : 除零异常
   value_error : 类型转换异常
   too_many_rows : 查询出多行记录,但是赋值给了rowtype记录一行数据变量
   no_data_found : 没有找到数据
       
   
   自定义异常:
       异常名  exception;
       raise 异常名          
*/
declare
   vi number;
   vrow emp%rowtype;
begin
   --vi := 8/0;  
   --vi := 'aaa';
   --select * into vrow from emp;
   select * into vrow from emp where empno=1234567;
exception
  when zero_divide then
    dbms_output.put_line('发生了除零异常');
  when value_error then
     dbms_output.put_line('发生了类型转换异常');
  when too_many_rows then
    dbms_output.put_line(' 查询出多行记录,但是赋值给了rowtype记录一行数据变量');
  when no_data_found then
    dbms_output.put_line('没有找到数据异常');
  when others then
     dbms_output.put_line('发生了其它异常' || sqlerrm);     
end;

--查询指定编号的员工,如果没有找到,则抛出自定义的异常
/*
     --错误的演示
     
     1.声明一个变量 %rowtype
     2.查询员工信息,保存起来
     3.判断员工信息是否为空
     4. 如果是 则抛出异常
*/
declare
  --   1.声明一个变量 %rowtype
  vrow emp%rowtype;
  --2 .声明一个自定义的异常
  no_emp exception;  
begin
  --查询员工信息,保存起来
  select * into vrow from emp where empno = 8888;   --抛出异常
  
  if vrow.sal is null then
    raise no_emp; --抛出自定义的异常
  end if;
exception
  when no_emp then
     dbms_output.put_line('输出了自定义的异常');  
  when others then
     dbms_output.put_line('输出了其它异常'||sqlerrm);  
end;

--查询指定编号的员工,如果没有找到,则抛出自定义的异常
/*
     游标来判断
       %found %notfound
    声明一个游标
    声明一个变量,记录数据
    从游标中取记录
       如果有,则不管它
       如果没有就抛出自定义的异常
*/
declare
  --声明游标
  cursor vrows is select * from emp where empno=8888;   
  --声明一个记录型变量
  vrow emp%rowtype;
  --声明一个自定义异常
  no_emp exception;  
begin
  --1.打开游标
  open vrows;
  --2.取数据
  fetch vrows into vrow;
  --3.判断游标是否有数据
  if vrows%notfound then
    raise no_emp;
  end if;
  close vrows;
exception
  when no_emp then
    dbms_output.put_line('发生了自定义的异常');
end;

/*
    存储过程: 实际上是封装在服务器上一段PLSQL代码片断,已经编译好了的代码
              1.客户端取调用存储过程,执行效率就会非常高效
         语法:
              create [or replace] procedure 存储过程的名称(参数名 in|out 参数类型,参数名 in|out 参数类型)
              is | as
               --声明部分
              begin
               --业务逻辑 
              end; 
             
              
*/
--给指定员工涨薪,并打印涨薪前和涨薪后的工资
/*
    参数 : in 员工编号
    参数 : in 涨多少
    
    声明一个变量 : 存储涨工资前的工资
    
    查询出当前是多少
    打印涨薪前的工资
    更新工资
    打印涨薪后的工资          
*/
create or replace procedure proc_updatesal(vempno in number,vnum in number)
is
   --声明变量.记录当前工资
   vsal number;    
begin
  --查询当前的工资
  select sal into vsal from emp where empno = vempno;
  --输出涨薪前的工资
  dbms_output.put_line('涨薪前:'||vsal);
  --更新工资
  update emp set sal = vsal + vnum where empno = vempno;
  --输出涨薪后的工资
  dbms_output.put_line('涨薪后:'||(vsal+vnum));
  --提交
  commit;
end;

--方式1
call proc_updatesal(7788,10);

--方式2 用的最多的方式
declare

begin
  proc_updatesal(7788,-100);
end;


/*
  存储函数: 实际上是一段封装是Oracle服务器中的一段PLSQL代码片断,它是已经编译好了的代码片段
        
        语法: 
             create [or replace] function 存储函数的名称(参数名 in|out 参数类型,参数名 in|out 参数类型) return 参数类型
             is | as
             
             begin
               
             end;
        存储过程和函数的区别:
             1.它们本质上没有区别
             2.函数存在的意义是给过程调用   存储过程里面调用存储函数
             3.函数可以在sql语句里面直接调用
             4.存储过程能实现的,存储函数也能实现,存储函数能实现的,过程也能实现
             
        默认是 in       
*/
--查询指定员工的年薪
/*
    参数 : 员工的编号
    返回 : 年薪          
*/
create or replace function func_getsal(vempno number) return number
is
  --声明变量.保存年薪
  vtotalsal number;     
begin
  select sal*12 + nvl(comm,0) into vtotalsal from emp where empno = vempno;
  return vtotalsal;
end;

--调用存储函数
declare
  vsal number;
begin
  vsal := func_getsal(7788);
  dbms_output.put_line(vsal);
end;


--查询员工的姓名,和他的年薪
select ename,func_getsal(empno) from emp;
--查询员工的姓名和部门的名称


--查询指定员工的年薪--存储过程来实现
--参数: 员工编号
--输出: 年薪
create or replace procedure proc_gettotalsal(vempno in number,vtotalsal out number)
is
       
begin
  select sal*12 + nvl(comm,0) into vtotalsal from emp where empno = vempno;
end;


declare
  vtotal number;
begin
  proc_gettotalsal(7788,vtotal);
  dbms_output.put_line('年薪:'||vtotal);
end;

select *  from emp where empno = 8888; 

/*
    JAVA调用存储过程
       JDBC的开发步骤:
          1.导入驱动包
          2.注册驱动
          3.获取连接
          4.获取执行SQL的statement
          5.封装参数
          6.执行SQL
          7.获取结果
          8.释放资源   
*/

/*
   封装一个存储过程 : 输出所有表中的记录
   
   输出类型 : 游标  
*/
create or replace procedure proc_getemps(vrows out sys_refcursor)
is

begin
  --1.打开游标, 给游标赋值
  open vrows for select * from emp;
end;

/*
   触发器: 当用户执行了 insert | update | delete 这些操作之后, 可以触发一系列其它的动作/业务逻辑
       作用 : 
            在动作执行之前或者之后,触发业务处理逻辑
            插入数据,做一些校验
            
       语法:
           create [or replace] trigger 触发器的名称
           before | after
           insert | update | delete 
           on 表名
           [for each row]
           declare
           
           begin
             
           end;
           
       触发器的分类:
           语句级触发器:   不管影响多少行, 都只会执行一次
           
           行级触发器:     影响多少行,就触发多少次
                  :old  代表旧的记录, 更新前的记录
                  :new  代表的是新的记录
       
*/
--新员工入职之后,输出一句话: 欢迎加入黑马程序员
create or replace trigger tri_test1
after
insert
on emp
declare

begin
  dbms_output.put_line('欢迎加入黑马程序员');
end;

insert into emp(empno,ename) values(9527,'HUAAN');

--数据校验, 星期六老板不在, 不能办理新员工入职
--在插入数据之前
--判断当前日期是否是周六
--如果是周六,就不能插入
create or replace trigger tri_test2
before
insert 
on emp
declare
 --声明变量
 vday varchar2(10);
begin
  --查询当前
  select trim(to_char(sysdate,'day')) into vday from dual;
  --判断当前日期:
  if vday = 'saturday' then
     dbms_output.put_line('老板不在,不能办理入职');
     --抛出系统异常
     raise_application_error(-20001,'老板不在,不能办理入职');
  end if;
end;

insert into emp(empno,ename) values(9528,'HUAAN2');

--更新所有的工资 输出一句话
create or replace trigger tri_test3
after
update
on emp 
for each row
declare

begin
  dbms_output.put_line('更新了数据');
end;

update emp set sal = sal+10;

--判断员工涨工资后的工资一定要大于涨工资前的工资
/*
   200 --> 100
   触发器 : before
      旧的工资 
      新的工资
      如果旧的工资大于新的工资 , 抛出异常,不让它执行成功   
      
      
   触发器中不能提交事务,也不能回滚事务 
*/
create or replace trigger tri_updatesal
before
update
on emp
for each row
declare

begin
  if :old.sal > :new.sal then
    raise_application_error(-20002,'旧的工资不能大于新的工资');
  end if;
end;

update emp set sal = sal + 10;
select * from emp;

update emp set sal = sal - 100;


/*
   模拟mysql中ID的自增属性 auto_increment 
   insert into person(null,'张三');  
   
   触发器:
   
   pid=1  insert  pid=1
   
   序列 : create sequence seq_person_pid;       
*/
create table person(
    pid number primary key,
    pname varchar2(20)   
);

insert into person values(null,'张三'); 

create sequence seq_person_pid;

--触发器
create or replace trigger tri_add_person_pid
before
insert
on person
for each row
declare

begin
  dbms_output.put_line(:new.pname);
  --给新记录 pid 赋值
  select seq_person_pid.nextval into :new.pid from dual;
end;

insert into person values(null,'张三'); 


select * from person;
 

猜你喜欢

转载自blog.csdn.net/qq_34475529/article/details/84070330