初步学习Oracle

一、Oracle前言

  • 数据定义语言(DDL):create drop alter

  • 数据操纵语言(DML):insert select delete update

  • 事务控制语言(TCL):commit savepoint rollback

  • 数据控制语言(DCL):grant revoke

--注意:建议Oracle代码不区分大小写:建议尽量用大写(因为写进去的小写最后会被转换为大写在去执行!)

--建议尽量每行代码的后面加一个分号,因为在PLSQL Developer中可以执行,但是在SQL Plus中却执行不出来结果,另外一种情况下也执行不了!(全部选起来,再去点击执行按钮会报错)。

二、Oracle中创建表和删除表以及添加约束和修改约束

创建表及约束:

create table student(
sno number not null primary key,
sname varchar2(30) not null unique,
ssex char(6) default '女',
sage number(3,0) check(sage>18 and sage<30),
saddress varchar2(50)
);
--删除刚才创建的表
drop table student;
--插入一条数据
insert into student
 (sno, sname, ssex, sage, saddress)
values
 (1, 'aa', '男', 20, '教室');
--查询
select * from student;  
--删除
delete student where sno=1;
--或者
delete from student where sno=1;
--修改
update student set sage = 21 where sno=1;

创建表及添加修改约束:

 --创建老师表
create table teacher(
tno number(10),
sno number,
name varchar(30)
);
--设置tno为主键
alter table teacher add constraint tno_pk primary key(tno);
--设置外键
alter table teacher add constraint sno_fk foreign key(sno) references student(sno);
--修改名字可以为空约束
alter table student modify(sname null);
--多行添加
insert into student
 (select 2,'张三','男',24,'长沙' from dual
 union
 select 3,'李四','男',25,'武汉' from dual
 union
 select 4,'王五','男',25,'武汉' from dual
);
--注意:多行插入也可以和MySQL一样

三、伪表和伪列

伪表:

--dual:伪表
select 1+1 from dual;
select lower('SDA') from dual;

伪列:

--伪列
--rowid rownum
--rowid:唯一性
--rowid:让每一条记录都唯一起来。
--伪列上查看前三条数据
select a.*,rownum from student a where rownum<4;
--或者
select a.*,rownum from student a where rownum<=3;
--注意:rownum只能小于或者小于等于,不能大于或单独的等于,oracle没有limit。

连接:

--||:连接符号,将两列并入一列
select sname||sage from student;

四、Oracle中创建表空间和删除

一、创建表空间:
--注意要用数据库管理员的身份创建(scott的权限不足)

--1.创建一个比较简单的表空间
create tablespace stu1
--创建表空间名为stu
--tablespace:表空间的关键字
datafile 'd:\stu1.dbf'
--数据文件保存在d:/stu.dbf (文件的后缀名为dbf)
--datafile:数据文件
--注意:Oracle中的字符串用单引号('')
size 100m
--大小为100m
--2.创建比较复杂的表空间
create tablespace stu
--创建表空间名为stu
--tablespace:表空间的关键字

datafile 'd:\stu.dbf'

size 100m

AUTOEXTEND ON NEXT 32M MAXSIZE UNLIMITED
--autoextend on:表空间大小不够用时自动扩展
--next 32m 自动扩展增量为32MB
--MAXSIZE UNLIMITED :最大空间:无限制
LOGGING
--logging 是对象的属性,创建数据库对象时,oracle 将日志信息记录到练级重做日志文件中。代表空间类型为永久型!
EXTENT MANAGEMENT LOCAL
--extent management local   代表管理方式为本地
SEGMENT SPACE MANAGEMENT AUTO;
--磁盘扩展管理方法:
--使用该选项时区大小由系统自动确定。由于 Oracle 可确定各区的最佳大小,所以区大小是可变的。
--删除表空间
drop tablespace stu1

ORACLE中,表空间是数据管理的基本方法,所有用户的对象要存放在表空间中,也就是用户有空间的使用权,才能创建用户对象.否则是不允许创建对象,因为就是想创建对象,如表,索引等,也没有地方存放,Oracle会提示:没有存储配额.

因此,在创建对象之前,首先要分配存储空间.分配存储,就要创建表空间:

  创建表空间示例如下:

CREATE TABLESPACE "SAMPLE"
LOGGING
DATAFILE D:\ORACLE\ORADATA\ORA92\LUNTAN.ora SIZE 5M
EXTENT MANAGEMENT LOCAL SEGMENT SPACE MANAGEMENT AUTO

上面的语句分以下几部分:

第一: CREATE TABLESPACE "SAMPLE"  创建一个名为 "SAMPLE" 的表空间.(对表空间的命名,遵守Oracle 的命名规范就可了.)

ORACLE可以创建的表空间有三种类型:

(1)TEMPORARY: 临时表空间,用于临时数据的存放;

创建临时表空间的语法如下:

CREATE TEMPORARY TABLESPACE "SAMPLE"......

(2)UNDO : 还原表空间. 用于存入重做日志文件.

创建还原表空间的语法如下:

CREATE UNDO TABLESPACE "SAMPLE"......

(3)用户表空间: 最重要,也是用于存放用户数据表空间

可以直接写成: CREATE TABLESPACE "SAMPLE"

TEMPORARY 和 UNDO 表空间是ORACLE 管理的特殊的表空间.只用于存放系统相关数据.

第二: LOGGING

有 NOLOGGING 和 LOGGING 两个选项,

NOLOGGING: 创建表空间时,不创建重做日志.

LOGGING 和NOLOGGING正好相反, 就是在创建表空间时生成重做日志.

用NOLOGGING时,好处在于创建时不用生成日志,这样表空间的创建较快,但是没能日志,数据丢失后,不能恢复,但是一般我们在创建表空间时,是没有数据的,按通常的做法,是建完表空间,并导入数据后,是要对数据做备份的,所以通常不需要表空间的创建日志,因此,在创建表空间时,选择 NOLOGGING,以加快表空间的创建速度.

第三: DATAFILE 用于指定数据文件的具体位置和大小.

如: DATAFILE D:\ORACLE\ORADATA\ORA92\LUNTAN.ora SIZE 5M

说明文件的存放位置是 D:\ORACLE\ORADATA\ORA92\LUNTAN.ora , 文件的大小为5M.

如果有多个文件,可以用逗号隔开:

DATAFILE D:\ORACLE\ORADATA\ORA92\LUNTAN.ora SIZE 5M,

D:\ORACLE\ORADATA\ORA92\dd.ora SIZE 5M

但是每个文件都需要指明大小.单位以指定的单位为准如 5M 或 500K.

对具体的文件,可以根据不同的需要,存放大不同的介质上,如磁盘阵列,以减少IO竟争.

指定文件名时,必须为绝对地址,不能使用相对地址.

第四: EXTENT MANAGEMENT LOCAL 存储区管理方法

在Oracle 8i以前,可以有两种选择,一种是在字典中管理(DICTIONARY),另一种是本地管理(LOCAL ),从9I开始,只能是本地管理方式.因为LOCAL 管理方式有很多优点.

在字典中管理(DICTIONARY): 将数据文件中的每一个存储单元做为一条记录,所以在做DM操作时,就会产生大量的对这个管理表的Delete和Update操作.做大量数据管理时,将会产生很多的DM操作,严得的影响性能,同时,长时间对表数据的操作,会产生很多的磁盘碎片,这就是为什么要做磁盘整理的原因.

本地管理(LOCAL): 用二进制的方式管理磁盘,有很高的效率,同进能最大限度的使用磁盘. 同时能够自动跟踪记录临近空闲空间的情况,避免进行空闲区的合并操作。

第五: SEGMENT SPACE MANAGEMENT

磁盘扩展管理方法:

SEGMENT SPACE MANAGEMENT: 使用该选项时区大小由系统自动确定。由于 Oracle 可确定各区的最佳大小,所以区大小是可变的。

UNIFORM SEGMENT SPACE MANAGEMENT:指定区大小,也可使用默认值 (1 MB)。

第六: 段空间的管理方式:

AUTO: 只能使用在本地管理的表空间中. 使用LOCAL管理表空间时,数据块中的空闲空间增加或减少后,其新状态都会在位图中反映出来。位图使 Oracle 管理空闲空间的行为更加自动化,并为管理空闲空间提供了更好的性,但对含有LOB字段的表不能自动管理.

MANUAL: 目前已不用,主要是为向后兼容.

第七: 指定块大小. 可以具体指定表空间数据块的大小.

创建例子如下:

1 CREATE TABLESPACE "SAMPLE"

2 LOGGING

3 DATAFILE D:\ORACLE\ORADATA\ORA92\SAMPLE.ora SIZE 5M,

4 D:\ORACLE\ORADATA\ORA92\dd.ora SIZE 5M

5 EXTENT MANAGEMENT LOCAL

6 UNIFORM SEGMENT SPACE MANAGEMENT

7* AUTO

表空间已创建。

要删除表空间,可以

DROP TABLESPACE SAMPLE;

五、Oracle中创建角色赋权和收权

--创建角色、赋权、收权时注意要用数据库管理员的身份创建(scott的权限不足)

--1.创建一个简单的角色
create user sb
--创建一个用户:用户名为sb
identified by 123
--该账号的密码为123

--2.创建一个带有表空间的角色
create user sc
--创建一个用户:用户名为sc
identified by 456
--该账号的密码为456
default tablespace stu
--默认表空间为:stu

--把CONNECT、RESOURCE角色授予用户sb
GRANT CONNECT,RESOURCE TO sb;
--允许用户查看 EMP 表中的记录
GRANT SELECT ON emp TO sb;
--允许用户更新 EMP 表中的记录
GRANT UPDATE ON emp TO sb;

--撤销用户epet的RESOURCE角色
REVOKE RESOURCE FROM sb;

--常用系统预定义角色
--CONNECT:临时用户。
--RESOURCE:更为可靠和正式的用户。
--DBA:数据库管理员角色,拥有管理数据库的最高权限。

六、PL/SQL

--打印Hello World
begin
dbms_output.put_line('Hello World1');//输出语句
dbms_output.put_line('Hello World2');
end;

--利用声明变量实现查询7369的所有信息
--%type:取现有的数据表中的数据的类型
--%rowtype:取表中一行的数据类型
declare
eid emp.empno%type:=7369; //将emp表中的empno列的数据类型赋给eid,并给eid赋值为7369
emprow emp%rowtype; //将emp表中的一行赋给emprow
begin
 select * into emprow from emp where empno=eid; //从emp表中取出一行,并赋值给emprow
dbms_output.put_line('编号为'||eid||'的员工姓名为'||emprow.ename);
end;

斐波那契数列

--斐波那契数列

--loop循环
declare
a number:=1;
b number:=0;
c number:=0;
i number:=1;
begin
 loop
  c:=a+b;
  a:=b;
  b:=c;
  i:=i+1;
   exit when i>6;
   end loop;
  dbms_output.put_line(c);
end;

--while循环
declare
a number:=1;
b number:=0;
c number:=0;
i number:=1;
begin
 while(i<=6)loop
c:=a+b;
a:=b;
b:=c;
i:=i+1;
 end loop;
dbms_output.put_line(c);
end;

--for循环
declare
a number:=1;
b number:=0;
c number:=0;
i number:=1;
begin
 for i in 1..30
   loop
    c:=a+b;
    a:=b;
    b:=c;
     end loop;
    dbms_output.put_line(c);
end;
--if-else语句
--查询员工编号为7369的薪水,如果薪水大于600输出高薪水,如果小于600底薪水
declare
eid number(10):=7369;
sal emp.sal%type;
begin
 select sal into sal from emp where empno=eid;
 if sal>600 then
  dbms_output.put_line('高薪水');
   else dbms_output.put_line('底薪水');
   end if;
end;

--查询员工编号为7369的薪水,如果薪水大于1500输出高薪水,如果小于1500-900中等薪水,
--小于900底薪水
declare
eid number(10):=7369;
sal emp.sal%type;
begin
 select sal into sal from emp where empno=eid;
 if(sal>1500) then
dbms_output.put_line('高薪水');
elsif(sal>900) then
dbms_output.put_line('中等薪水');
 else dbms_output.put_line('底薪水');
 end if;
end;

--case
--查询员工编号为7369的工资等级。注意:只能为固定值
--800 A     950   B   1100   C    else   no
--方法一:
declare
eid number(10):=7369;
sal emp.sal%type;
begin
 select sal into sal from emp where empno=eid;
 case sal
   when '800' then dbms_output.put_line('A');
   when '950' then dbms_output.put_line('B');
   when '1100' then dbms_output.put_line('C');
   else dbms_output.put_line('no');
 end case;
end;

函数递归

--递归实现1+2+3+4加到100的和
create or replace function test01(n in number)
return number is
begin
 if n=1 then return 1;
 else return (n+test01(n-1));
 end if;
 end test01;
 
select test01(100) from dual;
drop function test01;

--递归求出第21位 1,1,2,3,5,8,13,21...(此处非递归)
create or replace function test02(n in number)
return number is
a number(10):=1;
b number(10):=0;
c number(10):=0;
begin
 for i in 1..n
   loop
    c:=a+b;
    a:=b;
    b:=c;
     end loop;
     return c;
 end test02;

select test02(6) from dual;
drop function test02;

--1.编写一个函数,要求能将阿拉伯数字(a,b,c,d,e,f,g,h,i)分别替换为
--(1,2,3,4,5,6,7,8,9),非数字全部替换为0,禁止使用replace
create or replace function test03(str in varchar2)
return varchar2 is
newStr varchar2(100):='';
r varchar2(2):='';
begin
 for i in 1..length(str)
   loop
     select substr(str,i,1) into r from dual;
     case r
       when 'a' then newStr:=newStr||1;
       when 'b' then newStr:=newStr||2;
       when 'c' then newStr:=newStr||3;
       when 'd' then newStr:=newStr||4;
       when 'e' then newStr:=newStr||5;
       when 'f' then newStr:=newStr||6;
       when 'g' then newStr:=newStr||7;
       when 'h' then newStr:=newStr||8;
       when 'i' then newStr:=newStr||9;
         else newStr:=newStr||0;
     end case;
   end loop;
   return newStr;
 end test03;
 
select test03('abcdklgasngoeirg;ajldgqeoihoiqehglds') from dual;
drop function test03;

--2.要求编写函数,要求能将传进来的字符串反序输出,比如'abcdef',要求输出为'fedcba'
create or replace function test04(str in varchar2)
return varchar2 is
newStr varchar2(100):='';
r varchar2(1):='';
begin
 for i in 1..length(str)
   loop
    newStr:=substr(str,i,1)||newStr;
   end loop;
   return newStr;
 end test04;

select test04('123456789') from dual;
drop function test04;

异常

--系统自带异常
--no_data_found、too_many_rows......
--8.编写一个程序块,接受一个雇员名,从emp表中显示该雇员的工作岗位与薪水,
--若输入的雇员名不存在,显示“该雇员不存在”信息。
declare
ejob emp.job%type;
esal emp.sal%type;
ename1 emp.ename%type:='SMITH';
begin
 select job,sal into ejob,esal from emp where ename=ename1;
  dbms_output.put_line('工作岗位:'||ejob);
  dbms_output.put_line('薪水:'||esal);
  exception when no_data_found then dbms_output.put_line('该雇员不存在');
 end;
--自定义异常
declare
eid emp.empno%type:=7369;
esal emp.sal%type;
mye exception; --声明异常
begin
 select sal into esal from emp where empno=eid;
 if esal>2500 then
  dbms_output.put_line('不错不错');
   else
    raise mye; --抛异常
     end if;
    exception when mye then --处理异常
      dbms_output.put_line('加工资');
 end;

--
declare
n_s number(5);
e_my exception;
pragma exception_init(e_my,-20001);
begin
select count(ename) into n_s from emp where ename like 'S%';
if n_s=0 then
raise e_my;
end if;
dbms_output.put_line('数量是'||n_s);
exception
when e_my then
dbms_output.put_line('人员为空');
end;

游标

--5.某公司要根据雇员的职位来加薪,公司决定按下列加薪结构处理:
--             Designation   Raise
             -----------------------
--             Clerk         500
--             Salesman       1000
--             Analyst       1500
--             Otherwise     2000
--编写一个程序块,接受一个雇员名,从emp表中实现上述加薪处理。
declare
ejob emp.job%type;
esal emp.sal%type;
cursor myr(enames emp.ename%type) is select job,sal from emp where ename=enames for update of ename;
begin
 open myr('SMITH');
 fetch myr into ejob,esal;
 case ejob
   when 'CLERK' then
     update emp set sal=(esal+500) where current of myr;
    dbms_output.put_line('加薪后的薪水:'||(esal+500));
   when 'SALESMAN' then
     update emp set sal=(esal+1000) where current of myr;
    dbms_output.put_line('加薪后的薪水:'||(esal+1000));
   when 'ANALYST' then
     update emp set sal=(esal+1500) where current of myr;
    dbms_output.put_line('加薪后的薪水:'||(esal+1500));
--   when 'OTHERWISE' then dbms_output.put_line('加薪后的薪水:'||sal+2000);
   else
     update emp set sal=(esal+2000) where current of myr;
    dbms_output.put_line('加薪后的薪水:'||(esal+2000));
   end case;
   close myr;
 end;

select * from emp
--6.编写一个程序块,将emp表中雇员名全部显示出来。
declare
enames varchar(30);
cursor myr is select ename from emp;
begin
 open myr;
 loop
   fetch myr into enames;
   exit when myr%notfound;
  dbms_output.put_line(enames);
   end loop;
   close myr;
 end;


--7.编写一个程序块,将emp表中前5人的名字显示出来。
declare
enames varchar(30);
cursor myr is select ename from emp
where rownum<=5;
begin
 open myr;
 loop
 fetch myr into enames;
 exit when myr%notfound;
dbms_output.put_line(enames);
 end loop;
 close myr;
 end;
 
 --2. 使用For循环,接受一个部门号,从emp表中显示该部门的所有雇员的姓名,工作和薪水。
declare
--enames emp.ename%type;
--ejob emp.job%type;
--esal emp.sal%type;-
cursor myr(eid emp.deptno%type) is select ename,job,sal from emp where deptno=eid;
begin
   for i in myr(30)
   loop
     --fetch myr into enames,ejob,esal;
    dbms_output.put_line(i.ename||'::'||i.job||'::'||i.sal);
     --dbms_output.put_line(enames||'::'||ejob||'::'||esal);
     end loop;
 end;


select * from emp;

--3. 使用带参数的游标,实现第2题。
declare
--enames emp.ename%type;
--ejob emp.job%type;
--esal emp.sal%type;-
cursor myr(eid emp.deptno%type) is select ename,job,sal from emp where deptno=eid;
begin
   for i in myr(30)
   loop
     --fetch myr into enames,ejob,esal;
    dbms_output.put_line(i.ename||'::'||i.job||'::'||i.sal);
     --dbms_output.put_line(enames||'::'||ejob||'::'||esal);
     end loop;
 end;


--4.编写一个PL/SQL程序块,从emp表中对名字以“A”或“S”开始的所有雇员按他们基本薪水的10%给他们加薪。
declare
nums number(10):=0;
cursor myr is select * from emp where ename like 'A%' or ename like 'S%' for update
of ename;
begin
 for i in myr
   loop
    nums:=i.sal*1.1;
     update emp set sal=nums where current of myr;
     end loop;
 end;
 
select * from emp;
--5. emp表中对所有雇员按他们基本薪水的10%给他们加薪,如果所增加后的薪水大于5000卢布,则取消加薪。
declare
nums number(10);
cursor myr is select * from emp for update;
begin
 for i in myr
   loop
    nums:=i.sal*1.1;
     if nums<=5000 then
       update emp set sal=nums where current of myr;
       end if;
     end loop;
 end;

游标嵌套

--游标嵌套
--for循环
declare
cursor myr1 is select deptno from dept;
cursor myr2(deptno1 dept.deptno%type) is select ename from emp where deptno=deptno1;
begin
for i in myr1
loop
for j in myr2(i.deptno)
loop
dbms_output.put_line(i.deptno||':'||j.ename);
end loop;
end loop;
end;

--loop循环
declare
deptno1 dept.deptno%type;
enames emp.ename%type;
cursor myr1 is select deptno from dept;
cursor myr2(deptno2 dept.deptno%type) is select ename from emp where deptno=deptno2;
begin
open myr1;
loop
fetch myr1 into deptno1;
exit when myr1%notfound;
open myr2(deptno1);
loop
fetch myr2 into enames;
exit when myr2%notfound;
dbms_output.put_line(deptno1||' '||enames);
end loop;
close myr2;
end loop;
close myr1;
end;

REF游标和动态SQL

--游标嵌套
--for循环
declare
cursor myr1 is select deptno from dept;
cursor myr2(deptno1 dept.deptno%type) is select ename from emp where deptno=deptno1;
begin
 for i in myr1
   loop
      for j in myr2(i.deptno)
        loop
          dbms_output.put_line(i.deptno||':'||j.ename);
          end loop;
    end loop;
 end;
 
--loop循环
declare
deptno1 dept.deptno%type;
enames emp.ename%type;
cursor myr1 is select deptno from dept;
cursor myr2(deptno2 dept.deptno%type) is select ename from emp where deptno=deptno2;
begin
 open myr1;
 loop
   fetch myr1 into deptno1;
   exit when myr1%notfound;
   open myr2(deptno1);
   loop
     fetch myr2 into enames;
     exit when myr2%notfound;
    dbms_output.put_line(deptno1||' '||enames);
     end loop;
     close myr2;
   end loop;
   close myr1;
 end;


--REF游标
--1、REF游标分为强类型和弱类型

--2、强类型
--查询emp表中所有的数据
declare
type myr1 is ref cursor return emp%rowtype;
myr2 myr1;
enames emp%rowtype;
begin
 open myr2 for select * from emp;
 loop
   fetch myr2 into enames;
   exit when myr2%notfound;
  dbms_output.put_line(enames.ename);
   end loop;
   close myr2;
 end;
 
--3、弱类型
--查询emp表中所有的数据
declare
type myr1 is ref cursor;
myr2 myr1;
emps emp%rowtype;
begin
 open myr2 for select * from emp;
 loop
   fetch myr2 into emps;
   exit when myr2%notfound;
  dbms_output.put_line(emps.ename);
   end loop;
   close myr2;
 end;


--4、动态sql案例
declare
sal1 emp.sal%type:=1500;
sal2 emp.sal%type:=2000;
type myr1 is ref cursor;
myr2 myr1;
emps emp%rowtype;
begin
 open myr2 for 'select * from emp where sal>:1 and sal<:2 order by sal desc'
 using sal1,sal2;
 loop
   fetch myr2 into emps;
   exit when myr2%notfound;
  dbms_output.put_line(emps.ename);
   end loop;
   close myr2;
 end;


select ename from emp where sal>1500 and sal<2000;


select * from scott.student;


七、SQL高级

同义词

--同义词
--私有同义词和公有同义词
--创建一个同义词
create synonym emm for scott.emp;
--删除同义词
drop synonym emm;
--创建一个同义词
create or replace synonym a for scott.emp;
--运用
select * from a;
--创建一个公有的同义词
grant create public synonym to scott;
create or replace public synonym b for scott.emp;
create or replace public synonym c for scott.emp;
select * from b;
select * from c;
--授权
grant drop public synonym to scott;
drop public synonym b;
--收权
revoke drop public synonym from scott;

序列

--序列
create sequence aa
start with 1
increment by 1
maxvalue 100
minvalue 1
--查询序列
select aa.nextval from dual;
--查看当前值
select aa.currval from dual;
--删除序列
drop sequence aa;
--修改序列
alter sequence aa maxvalue 1000;
--序列使用
create table stu(
sid number,
names varchar2(10)
);

insert into stu values(aa.nextval,'zzz');
select * from stu;
drop table stu;

视图、索引

--视图
create or replace view bb
as
select * from stu;

create or replace force view cc
as
select * from stu;

drop view aa;
drop view cc;

--索引
create index dd on stu(sid);
drop index dd;

存储过程

--存储过程
--不带参数存储过程
create or replace procedure getname
as
enames varchar2(30);
begin
 select ename into enames from emp where empno=7369;
dbms_output.put_line(enames);
 end;

--调用
begin
getname;
 end;
call getname();
drop procedure getname;

--带参数的存储过程
--根据员工编号查询的名字。
create or replace procedure getnames(eno number)
as
enames varchar2(30);
begin
 select ename into enames from emp where empno=eno;
dbms_output.put_line(enames);
exception when no_data_found then
  dbms_output.put_line('此人不存在');
   when others then
    dbms_output.put_line('有错!');
 end;
 
--调用
begin
getnames(131);
end;
call getnames(131);

--in和out参数(只能用begin  end;调用)
--根据编号查询名字(名字要返回出来,存储过程中不打印)
create or replace procedure selectname(eid in number ,enames out varchar2)
as
enames1 varchar2(30);
begin
 select ename into enames1 from emp where empno=eid;
enames:=enames1;
 end;

--调用
declare
eid number(6):=7369;
ename varchar2(30);
begin
selectname(eid,ename);
dbms_output.put_line(ename);
 end;
 

--c.in out 参数
--实现a 和b的值交换。
create or replace procedure selectname(a in out number,b in out number)
as
c number(4);
begin
c := a;
a := b;
b := c;
 end;

--调用
declare
a number(4):=10;
b number(4):=20;
begin
selectname(a,b);
dbms_output.put_line('原来a为10,a:'||a);
dbms_output.put_line('原来6为20,b:'||b);
 end;

--总结:
--in参数:只作为参数传进去。
--out参数:返回的结果。
--in out参数:既要作为参数传进去,又要作为结果返回出来。

--存储过程的调用
--begin end;可以调用所有的存储过程
--call只能调用带参数的存储过程。调用无参数的时要加().不建议使用。容易和创建的()混淆。

触发器

--不能删除李文才
--创建触发器
create or replace trigger tridel  --创建触发器
after delete--什么操作
on stuInfo--表
for each row --行触发
begin
  --条件
  if(:old.stuName='李文才') then
  raise_application_error(-20004,'该生不能删除!');
  end if;
  end;
 
--序列
create sequence a
start with 0
increment by 1
maxvalue 2000
minvalue 0

create table s3(
no number(6),
name varchar2(30)
)

insert into s3(name) values('cc')

--创建触发器
create or replace trigger triInsert
before insert
on s3
for each row
 begin
   :new.no:=a.nextval;
   end;
   
select * from s3;
--禁用触发器
alter trigger triInsert disable
--启用
alter trigger triInsert enable
--删除触发器
drop trigger triInsert
 
 
--触发器
--表级触发器
create or replace trigger modify_stu
before insert or update or delete on student
begin
  if deleting then
    raise_application_error(-20001,'该表不允许删除数据');
  elsif updating then
    raise_application_error(-20002,'该表不允许修改数据');
  elsif inserting then
    raise_application_error(-20003,'该表不允许插入数据');
   end if;
end;

--行级触发器
--after
--创建触发器:将对student表的操作都记录到stu_log表中(update of 用于指定一个
--或多个字段,指定字段被更新时才会触发触发器)
create or replace trigger modify_stu
after insert or delete or update of stu_name
on student
for each row
 begin
   if inserting then
     insert into stu_log values(1,'insert',sysdate,:new.stu_name);
  elsif deleting then
      insert into stu_log values(2,'delete',sysdate,:old.stu_name);
  elsif updating then
     insert into stu_log values(3,'update_old',sysdate,:old.stu_name);
     insert into stu_log values(4,'update_new',sysdate,:new.stu_name);
    end if;
end;

--before
--创建触发器:实现id的隐式自增
create or replace trigger modify_stu
before insert on student
for each row
declare
next_id number;
begin
 select seq_test.nextval into next_id from dual;
 :new.id :=next_id;
end;

程序包

--程序包
--分为两部分:规范、主体
--规范
--1.程序包(函数和存储过程)
--存储过程(根据编号查名字)
--函数(根据编号查名字)
--规范部分
create or replace package pg is--或者as   创建程序包规范
procedure noname(eid number);--声明存储过程
function selectname(eid number) return varchar2;--声明函数
end pg;--结束程序包规范
--主体
create or replace package body pg is--创建程序包主体
procedure noname(eid number)--完成储存过程的主体
is
enames varchar2(30);
begin
 select ename into enames from emp where empno=eid;
dbms_output.put_line(enames);
 end;
--函数
function selectname(eid number) return varchar2--完成函数体
is
enames varchar2(30);
begin
 select ename into enames from emp where empno=eid;
 return enames;
 end;
end pg;

--删除规范
drop package pg;
--删除主体
drop package body pg;

--执行顺序问题:先执行规范,再执行主体。

--调用存储过程
call pg.noname(7369);
begin
pg.noname(7369);
 end;
--调用函数
select pg.selectname(7369) from dual;


--2.程序包(存储过程和游标嵌套使用)
--根据编号查询
--规范
create or replace package pb is
cursor c_emp(eid number) return emp%rowtype;--游标声明
procedure pro;--根据编号查询
end pb;

--主体
create or replace package body pb is
cursor c_emp(eid number) return emp%rowtype --声明游标
is
select * from emp where empno=eid;
procedure pro--声明存储过程
is
emprow emp%rowtype;
begin
 open c_emp(7369);
 fetch c_emp into emprow;
dbms_output.put_line(emprow.ename);
 close c_emp;--结束游标
 end;--结束存储过程
 end pb;--结束程序包


--调用
begin
pb.pro;
 end;

事务


--commit:提交
--rollback:回滚
--savepoint:保存点

--commit:提交
--自动提交:(关键字有:alter 、 create 、 drop 、 grant 、 revoke等)
--显示提交:(关键字有:insert、 update 、delete 等)
--rollback:回滚
--savepoint:保存点

--创建表
create table stu(
sno number(3),
sname varchar2(15)
);

select * from stu;

insert into stu(sno, sname) values(1, 'aa');
commit;

insert into stu(sno, sname) values(2, 'bb');

select * from stu;

insert into stu(sno, sname) values(2, 'bb');
commit;

insert into stu(sno, sname) values(3, 'bb');
rollback;

insert into stu(sno, sname) values(4, 'bb');
insert into stu(sno, sname) values(5, 'bb');
savepoint aa;
insert into stu(sno, sname) values(6, 'bb');
insert into stu(sno, sname) values(7, 'bb');
insert into stu(sno, sname) values(8, 'bb');
rollback to aa;

--总结:
--commit:对显示操作,进行数据的提交
--rollback:回滚到上次提交的位置。
--savepoint:设置一个保存点。可以回滚到设置的那个点的位置。
--PL/SQL Developer:软件在关闭的时候会帮我们提交我们没有提交的数据。

八、SQL优化

--数据库性能化

--数据库性能优化采取的工作可以分为6个部分。
--1.优化数据库结构设计。
--2.优化SQL语句。
--3.调整服务器内存分配。
--4.调整硬盘I/O。
--5.调整操作系统参数。
--6.使用Oracle工具优化。

--SQL语句优化。
--1.选择合理的表名顺序
--注意:列少的应放在最后面。(因为从右往左解释)。
select * from emp;--8列
select * from dept;--3列
--性能差
select * from dept a,emp b
where a.deptno=b.deptno;
--性能好
select * from emp b,dept a
where a.deptno=b.deptno;

--2.避免使用*
--差
select * from dept;
--好
select deptno,dname,loc from dept;

--3.高效删除重复的记录。
delete from emp a
where a.rowid > (select min(x.rowid)from emp x where x.empno=a.empno);

--1.
select * from student;
--2.
select a.*,a.rowid from student a;
--3.
select min(x.rowid)from student x;
--4.
select * from student a
where a.rowid > (select min(x.rowid)from student x where x.sno=a.sno);
--0  1
-- 0 1 2 3 4 5 6 7
-- 0 1 2 3 4 5 6 7 8 9
-- 0 1 2 3 4 5 6 7 8 9 A B C D E F 10

--4.减对表的查询(子查询)
select * from emp;
--3次
select * from emp where sal=(select max(sal) from emp) and comm=(select max(comm) from emp);
--优化
select * from emp where (sal,comm)=(select max(sal),max(comm) from emp);
--总结:适当的可以用where条件代替子查询

--5.使用表别名
select a.ename,b.dname from emp a,dept b where a.deptno=b.deptno;

--6.exists代替in
--找出deptno的薪水
select ename from emp where deptno=20;

select sal from emp where ename in(select ename from emp where deptno=20);

select sal from emp a where exists(select * from emp b where deptno=20 and a.empno=b.empno );

--7.用not exists 代替 not in.
select sal from emp where ename not in(select ename from emp where deptno=20);

select sal from emp a where not exists(select * from emp b where deptno=20 and a.empno=b.empno );
--8.用表连接替换exists
select ename from emp a where exists(select * from dept b where a.deptno=b.deptno and deptno=30);

--优化
select ename from emp a ,dept b where a.deptno=b.deptno and b.deptno=30;

select ename from emp a
inner join
dept b
on a.deptno=b.deptno and b.deptno=30;

--9.用exists替换distinct
select distinct deptno from emp;
--优化
select deptno from dept a where exists(select deptno from emp b where a.deptno=b.deptno);
--10.索引优化。

--总结:
--1.在两表联查时,列少的写后面,l列多的写前面。
--2.查询语句时,尽量少用*
--3.尽量用where条件代替两表联查。
--4.用exists替换distinct
--5.使用表别名
--6.exists代替in

--这里优化只是属于一部分。



posted @ 2021-08-02 17:01  zheng_newbie  阅读(52)  评论(0编辑  收藏  举报