Oracle安装

安装教程1 安装教程2

Mysql 管理员 root 端口:3306

Oracle 管理员sys system 端口:1521

服务

两个服务必须开启

必开:

orcl…

OracleOraDb11g_home1TNSListener:监听器服务,远程访问的时候需要

服务

数据类型

  • 字符型
数据类型说明
CHAR(n)固定长度字符串,n表示存储字符数量,长度<=2000字节
VARCHAR2(n)可变长字符串,n表示存储字符数量,长度<=4000字节
LONG可变长度字符串,长度<=2GB
RAW可变长度二进制字符串,长度<=2000字节
  • 数值型
数据类型说明
NUMBER(p,s)数值类型,p表示精度,s表示小数位数
FLOAT浮点数类型,相当于NUMBER(38),双精度
INTEGER整数类型

注:NUMBER类型:P是精度,表示有效数字的位数,最多不能超过38个有效数字。S是小数位数,表示从小数点到最低有效数字的位数,它为负数时,表示从最大有效数字到小数点的位数。指定了P值,没有指定S,那么S默认是0。最大的有效数字是最左边的非零数字,而最小有效位是最右边的数字。Oracle保证数字的可移植性精度高达20 base-100 digits,相当于39位或40位十进制数字,取决于小数点的位置。如果P和S都省略了,S的值是变化的,小数点前的数字位数和小数点后的数字位数相加为40(有时候又是39)。小数点和负号不计入有效位数。

数值型的数据类型在底层实现上,都是用NUMBER来保存。

  • 日期/时间型
数据类型说明
DATE日期类型,精确到秒
TIMESTAMP(n)日期类型,精确到微秒,n(0~9)表示微秒的精确范围,默认是6
  • 大对象(LOB)型
数据类型说明
BFILE存放在数据库外的二进制数据,指向服务器文件系统上的文件定位器,长度<=4GB
BLOB二进制数据,长度<=4GB
CLOB字符数据,长度<=4GB
  • ROWID类型
数据类型说明
ROWID数据表中记录的唯一行号
UROWID通用的ROWID,既可以保存物理的ROWID,也可以保存逻辑的ROWID

一个汉字3个字节 varchar(6) 6个字节

创建用户

-- 创建用户
create user temo IDENTIFIED by 12345 DEFAULT tablespace users;

添加时间格式日期

TO_DATE('2020-6-1 14:45:21','yyyy-MM-dd HH24:mi:ss')

添加语句

insert into lolgame values(2,'易','剑圣',3200.15,TO_DATE('2020-6-1 14:45:21','yyyy-MM-dd HH24:mi:ss'));

系统时间

--系统时间
select SYSDATE   from dual

时间戳

--时间戳
select SYSTIMESTAMP from dual

添加表属性

-- 添加表属性
ALTER TABLE LOLGAME ADD name VARCHAR(12);
-- 添加区ID
ALTER TABLE LOLGAME ADD areaid INTEGER;

修改表属性

-- 修改表属性
ALTER table lolgame MODIFY NICKNAME VARCHAR2(16);

删除表属性

-- 删除表属性
ALTER table LOLGAME DROP COLUMN name;

删除表

-- 删除表 
drop TABLE LOLGAME;

设置外键

-- 外键
ALTER TABLE 从表 add constraint 名称 foreign key(列名) references 主表(列名)

ALTER TABLE LOLGAME add constraint f_area foreign key(areaid) references Area(id);

检查约束

-- 检查约束 
   --返回price只能在 0-8000内
ALTER TABLE LOLGAME add constraint ck_price CHECK(price BETWEEN 0 and 8000)

数值函数

ROUND(数值,保留位数) 四舍五入

  --ROUND(数值,保留位数) 四舍五入
select ROUND(8.52,1) from dual

TRUNC(数值,截取位数) 截取

  --TRUNC(数值,截取位数) 截取
SELECT TRUNC(8.5234,2) from dual;

MOD (数值1,数值2) 取余

  --MOD (数值1,数值2) 取余
select MOD(5,17) from dual;

字符串函数

lower(转换值) 转换小写

   --lower(转换值) 转换小写
select lower('WJ') from dual;

UPPER(转换值) 转换大写

 -- UPPER(转换值) 转换大写
select UPPER('nj') from dual;

concat(字段1,字段2) 连接 字段1和字段2拼接

--concat(字段1,字段2) 连接 字段1和字段2拼接
select CONCAT(AREAID,NICKNAME) from LOLGAME;

SUBSTR(字符串, 第几个开始(1开始), 截取的长度) 截取字符串

 --SUBSTR(字符串, 第几个开始(1开始), 截取的长度) 截取字符串
select SUBSTR('hellogoodmorinig',4,2) from dual

LENGTH(字符串) 长度个数

  --LENGTH(字符串) 长度个数
select LENGTH('集运') from dual;

INSTR(字符串,查找的字符串) 字符串的位置(1开始)

--INSTR(字符串,查找的字符串) 字符串的位置(1开始)
select INSTR('helloword','h') from dual;

LPAD(内容, 填几个, 填充的内容) 填内容 &&&nj

--LPAD(内容, 填几个, 填充的内容) 填内容 &&&nj
select LPAD('nj', 5,'&') from dual;

TRIM(ch) 删除空格默认  TRIM(‘H’ from ‘HELLO’) 删除H 只删除左右

--TRIM(ch) 删除空格默认  TRIM('H' from 'HELLO') 删除H 只删除左右
select TRIM('H' from 'HELLO') from dual;

日期函数

MONTHS_BETWEEN(date1, date2) 计算两个日期间的月数

  --MONTHS_BETWEEN(date1, date2) 计算两个日期间的月数
select MONTHS_BETWEEN(TO_DATE('2021-6-1','yyyy-MM-dd'),TO_DATE('2020-6-1','yyyy-MM-dd')) from dual;

ADD_MONTHS(时间, 几个月) 在日期上加上指定的月份

 --ADD_MONTHS(时间, 几个月) 在日期上加上指定的月份
select ADD_MONTHS(TO_DATE('2021-6-1', 'yyyy-MM-dd'),2) from dual;

NEXT_DAY(时间, 星期几); 当前日期的下一条

 --NEXT_DAY(时间, 星期几); 当前日期的下一条 
select NEXT_DAY(TO_DATE('2021-6-1', 'yyyy-MM-dd'),'星期一') from dual;
select NEXT_DAY(SYSDATE, '星期一') from dual;

LAST_DAY(date); 日期的最后一天

 --LAST_DAY(date); 日期的最后一天 
select LAST_DAY(TO_DATE('2021-6-1', 'yyyy-MM-dd')) from dual;

ROUND(date, fmt) 日期四舍五入

 --ROUND(date, fmt) 日期四舍五入
select ROUND(TO_DATE('2021-6-15', 'yyyy-MM-dd'),'month') from dual; 
select ROUND(TO_DATE('2021-7-15', 'yyyy-MM-dd'),'year') from dual; 
select ROUND(TO_DATE('2021-7-5', 'yyyy-MM-dd'),'day') from dual; 

TRUNC(date, fmt) 截取指定的日期

  --TRUNC(date, fmt) 截取指定的日期 
select TRUNC(TO_DATE('2020-12-12', 'yyyy-MM-dd'), 'month') from dual;

连接

内连接 inner join

--内连接
select * from area a,LOLGAME g where a.ID=g.AREAID
--内连接
select * from area a inner join LOLGAME g on a.ID=g.AREAID

左外连接 left join

--左外连接
select * from area a left join LOLGAME g on a.ID=g.AREAID

右连接 right join

--右外连接
select * from area a right join LOLGAME g on a.ID=g.AREAID

union 联合查询

--union 联合查询
select * from LOLGAME where AREAID=1
UNION
select * from LOLGAME where AREAID=2

交集查询 intersect

–intersect 交集查询 两者都满足条件的

--intersect 交集查询 两者都满足条件的
select * from LOLGAME
intersect 
select * from LOLGAME where AREAID=1;

MINUS 差集

--MINUS 差集
select * from LOLGAME where AREAID>1
MINUS
select * from LOLGAME where AREAID=2;

事务

什么是事务

在数据库中事务是工作的逻辑单元,一个事务是由一个或多个完成一组的相关行为的SQL语句组成,通过事务机制确保这一组SQL语句所作的操作要么完全成功执行,完成整个工作单元操作,要么一点也不执行

特性

确保数据库的完整性。

锁(行级锁 表级锁)

进入命令查询

cmd sqlplus

行级锁解释

如果你正在修改某一行,那么其他使用的人可以更新除了这一行之外的数据,而你修改的这一行是不允许被修改的  不允许在同一时刻其他用户修改同一行数据

锁的作用

防止多人使用时数据的不一致性

自动应用行级锁

insert update delete 都会自动加行级锁
select ... for update 才会加锁(for update) 查询时 其他用户不能进行增删改操作

解锁

commit 提交后解锁
rollback 回退解锁

解锁

表级锁

表级锁类型

1)行共享 (ROW SHARE) – 禁止排他锁定表
2)行排他(ROW EXCLUSIVE) – 禁止使用排他锁和共享锁
3)共享锁(SHARE)
4)锁定表,仅允许其他用户查询表中的行
     禁止其他用户插入、更新和删除行
     多个用户可以同时在同一个表上应用此锁
5)共享行排他(SHARE ROW EXCLUSIVE) – 比共享锁更多的限制,禁止使用共享锁及更高的锁
6)排他(EXCLUSIVE) – 限制最强的表锁,仅允许其他用户查询该表的行。禁止修改和锁定表

排他锁(exclusive)

-- 表锁定(exclusive:排他锁) 只能查询
-- 仅允许其他用户查询该表的行。禁止修改和锁定表
lock table 表名 in 锁名 mode nowait;
lock table lolgame in exclusive mode nowait;

行共享(ROW SHARE)

-- 允许用户进行任何操作
lock table 表名 in 行共享 mode nowait;
lock table lolgame in row share mode nowait;

对象

创建修改

可以创建也可以修改

create or REPLACE  语句

同义词

作用

简化SQL语句

同义词创建

-- sys账号需要查询scott下的表 在sys下需要 scott.表名
select * from scott.AREA;
-- 创建一个同义词
   --私有
create synonym 别名 for 账号.表名
create SYNONYM lol for SCOTT.LOLGAME;
   --公有
create public synonym 别名 for 账号.表名
create PUBLIC SYNONYM lol for SCOTT.LOLGAME;
--创建同义词后查询
select * from lol//结果是查询出scott账号下的lolgame表

同义词修改

--修改同义词名
create or replace synonym 别名 for 账号.表名
create or REPLACE SYNONYM lol for SCOTT.LOLGAME;

删除同义词

--删除
DEOP SYNONYM 创建同义词时的别名
DROP SYNONYM lol;

序列

作用

生成唯一 连续序号

创建序列(自增)

--创建序列 1000开始值 从1000开始每次增加1
create sequence 名字 start with 起始数;
create sequence stu_seq start WITH 1000;

使用序列

--使用序列  stu.seq为创建序列的名字  nextval:序列下一个值
insert into 表名 values(序列名.nextval,'值2','值3','值4');
insert into student VALUES(stu_seq.nextval,'李四','456',SYSDATE);

查询当前序列

--查询当前序列 currval:当前序列值 需要先使用序列
select 创建的序列名.currval from 表名
select stid_seq.currval from dual;

序列自减

start with 5 :开始值为5  increment by:每次-1 maxvalue 5:最大值5 
create sequence teid_sq START WITH 5 INCREMENT by -1 maxvalue 5;

修改删除序列

--修改序列 stu_seq为 创建序列时的名字 不能修改start值(起始值)
alter sequence stu_seq 参数
--删除序列
drop sequence stu_seq

视图

作用

–提供了另外一种级别的表安全性

–隐藏的数据的复杂性

–简化的用户的SQL命令

–隔离基表结构的改变

–通过重命名列,从另一个角度提供数据

创建视图

--创建视图
create view 视图名 as sql语句;
create view jiuyunst as select ID,NAME,createtime from student;

视图执行删除

delete from 视图名 where name='?'
delete from jiuyunst where NAME='李四';

删除视图

drop view 视图名

WITH CHECK OPTION

可以对数据进行增删改查 ,但是需要视图能够查询到的数据

只能对视图能够查询的数据进行增删改查

-- 创建视图是加上 WITH CHECK OPTION 只能删除视图里面有的的数据
create or REPLACE view jiuyunst as select ID,NAME,createtime from student where ID>1 WITH CHECK OPTION;

WITH READ ONLY

--创建视图上加上 HITH READ ONLY(只读) 只能执行查询
create or REPLACE view jiuyunst as select ID,NAME,createtime from student where ID>1 WITH READ ONLY;

索引

主键自带索引

作用

查询数据的更快 提高sql语句的执行性能

聚集索引

聚集索引类似词典的拼音查找 同音的在一块

非聚集索引

非聚集索引类似偏旁查找

创建索引

--创建索引
create index 索引名 on 表名(需要加索引的字段)
create index stupass_index ON student (pass);

唯一索引

确保定义索引的列没有重复值

--唯一索引
create UNIQUE INDEX 索引名 on 表名(表需要索引字段)
CREATE UNIQUE INDEX sname_index ON student(name);

删除索引

--删除索引
DROP INDEX 创建索引时的名字
DROP index loln_index;

PLSQL

1、基本语法 Declare begin exception end

2、记录类型 --类似对象

3、流程控制 条件 循环

4、游标 类似集合

5、异常处理 +事务

6、函数 储存过程

7、触发器

基本语法

//关键字 DECLARE ....BEGIN .....END;
DECLARE
变量
BEGIN
赋值
输出
END;

---------------------
DECLARE
v_id NUMBER(10);
v_name VARCHAR(20);
BEGIN
v_id:=88;
SELECT NAME INTO v_name FROM STUDENT WHERE ID=1;
dbms_output.put_line(v_name);
dbms_output.put_line('姓名:'||v_name);
dbms_output.put_line('ID:'||v_id);
END;

单独赋值

//变量名 :=
DECLARE
v_id NUMBER(10)
BEGIN
v_id:=88
end;

定义变量

DECLARE 
变量名 类型
......
BEGIN
......
END;
--------
DECLARE
v_id NUMBER(10);
v_name VARCHAR(20);
BEGIN
.......
END;

输出语句

//单独输出变量
dbms_output.put_line(v_name);
//拼接变量 ||
dbms_output.put_line('姓名:'||v_name);

查询赋值

// 查询赋值 查询出单独一个赋值 
//select name INTO 定义的变量 from 表名 where 条件
DECLARE
v_id NUMBER(10);
v_name VARCHAR(20);
BEGIN
v_id:=88;
SELECT NAME INTO v_name FROM STUDENT WHERE ID=1;
dbms_output.put_line(v_name);
dbms_output.put_line('姓名:'||v_name);
dbms_output.put_line('ID:'||v_id);
END;

行变量语法

DECLARE
变量名 表名%rowtype;
BEGIN
select * into 变量名 from 表名 where 条件
//输出
dbms_output_put_line('ID:'||变量名.表字段)
END;
------------------------
DECLARE
st1 STUDENT%rowtype;
BEGIN
select * into st1 from STUDENT where ID=1;
dbms_output.put_line('姓名:'||st1.NAME);
dbms_output.put_line('ID:'||st1.ID);
END;

行变量语法

表类型赋值

DECLARE
v_id STUDENT.ID%TYPE; //变量名 表名.表字段%type
v_name STUDENT.NAME%TYPE;
v_pass STUDENT.PASS%TYPE;
v_createtime STUDENT.CREATETIME%TYPE;
BEGIN
SELECT ID INTO v_id FROM STUDENT WHERE id=1;
SELECT NAME INTO v_name FROM STUDENT WHERE id=1;
SELECT PASS INTO v_pass FROM STUDENT WHERE id=1;
SELECT CREATETIME INTO v_createtime FROM STUDENT WHERE id=1;
//输出
dbms_output.put_line('ID:'||v_id||'  '||'姓名:'||v_name||'  '||'密码:'||v_pass||'  '||'创建时间:'||v_createtime);
END;

表类型赋值

IF条件判断

--条件判断
DECLARE
week NUMBER(10):=3;
BEGIN
IF week=1 THEN
dbms_output.put_line(week||'去上课!');
ELSE
dbms_output.put_line(week||'休息!');
END IF;
END;

IF条件判断

多重条件判断

//语法
if 条件 THEN
操作1
ELSIF 条件 THEN
操作2
ELSIF 条件 THEN
操作3
ELSE
操作4
END IF;



--条件判断
DECLARE
week NUMBER(10):=10;
BEGIN
IF week=1 THEN
dbms_output.put_line(week||'去上课!');
ELSIF week=2 THEN
dbms_output.put_line(week||'休息2!');
ELSIF week=3 THEN
dbms_output.put_line(week||'休息3!');
ELSIF week=4 THEN
dbms_output.put_line(week||'休息4!');
ELSIF week=5 THEN
dbms_output.put_line(week||'休息5!');
ELSE
dbms_output.put_line(week||'唯一性!');
END IF;
END;

多重条件判断

SWITCH CASE判断

//语法
case 变量
when 条件或值 THEN
操作1
when 条件或值 THEN
操作2
when 条件或值 THEN
操作3
else//可以不写
操作4
end case;

--Case判断
DECLARE
week NUMBER(10):=4;
BEGIN
case week
WHEN 1 THEN
dbms_output.put_line(week||'CASE1!');
WHEN 2 THEN
dbms_output.put_line(week||'CASE2!');
WHEN 3 THEN
dbms_output.put_line(week||'CASE3!');
ELSE
dbms_output.put_line(week||'CASE4!');
END case;
END;

switch

loop循环

//语法
loop
语句;
exit when 条件;//退出条件
end loop;

---------------------------------

--循环1-10
DECLARE
num NUMBER(10):=0;
BEGIN
LOOP
  num:=num+1;
dbms_output.put_line(num);
exit WHEN num=10;
END LOOP;
END;

loop

while循环

//语法
while 条件 loop
操作
end loop;
-------------------

--while循环
DECLARE
num NUMBER(10):=0;
BEGIN
while num<10 loop
num:=num+1;
dbms_output.put_line(num);
end loop;
END;

while

for循环

//语法
DECLARE
BEGIN
for 变量 in 条件 loop
操作
end loop;
end;
-----------------------------
--for循环 1-10
DECLARE

BEGIN
for k in 1..10 loop
dbms_output.put_line(k);
end loop;
END;

for循环

for循环反转

//语法
for 变量 in REVERSE 条件 loop
操作
end loop;

-------------------------

-- for循环反转REVERSE
DECLARE

BEGIN
for k in REVERSE 1..10 loop
dbms_output.put_line(k);
end loop;
END;

for循环反转

GOTO跳出循环

for 变量 in 条件 loop
操作
if 条件 then
goto 变量2
end if;
end loop;
<<变量2>>
操作



--------------------------

--for循环 到5跳出
DECLARE

BEGIN
for k in 1..10 loop
dbms_output.put_line(k);
if k=5 THEN
GOTO label;
END IF;
end loop;
<<label>>
dbms_output.put_line('跳出循环!');
END;

日期转换

TO_CHAR(变量名,'yyyy-MM-dd HH24:mi:ss')

TO_CHAR(v_creatime,'yyyy-MM-dd HH24:mi:ss')

---------
DECLARE 
v_ID STUDENT.ID%TYPE;
v_NAME STUDENT.NAME%TYPE;
v_PASS STUDENT.PASS%TYPE;
v_creatime STUDENT.CREATETIME%TYPE;
BEGIN
SELECT ID INTO v_ID from STUDENT where ID=1;
SELECT NAME INTO v_NAME from STUDENT where ID=1;
SELECT PASS INTO v_PASS from STUDENT where ID=1;
SELECT CREATETIME INTO v_creatime from STUDENT where ID=1;
dbms_output.put_line('ID:'||' '||v_ID);
dbms_output.put_line('NAME:'||' '||v_NAME);
dbms_output.put_line('PASS:'||' '||v_PASS);
dbms_output.put_line('CREATETIME:'||' '||TO_CHAR(v_creatime,'yyyy-MM-dd HH24:mi:ss'));
END;

日期转换

游标

游标是指向此上下文区域的指针。PL/SQL通过游标控制上下文区域,游标保存SQL语句返回的行(一个或多个)。 游标所在的行集称为活动集。处理结果集

1、定义 CURSOR 游标名 IS SQL语句;

2、打开 open 游标名

3、使用

4、关闭 close 游标名

限制行数

where rowunm<=5 行数5

显式游标

DECLARE
变量名 表.字段%type;
cursor 游标名 is sql语句 //定义游标
BEGIN
open 游标名; //打开游标
loop //loop循环
FETCH 游标名 into 变量; //复制变量
exit when 游标%notfound; //notfund:未找到 没有找到游标时退出循环
dbms_output.put_line(变量); //输出赋值后的变量
end loop;
close 游标名; 关闭游标
end;
-------

--loop游标
DECLARE
v_name EMP.ENAME%TYPE;
cursor v_cur is select ENAME from EMP;
BEGIN
open v_cur;
loop
 FETCH v_cur into v_name;
 exit when v_cur%notfound;
 dbms_output.put_line(v_name);
end loop;
close v_cur;
end;

--------
--while游标
DECLARE
 CURSOR V_CUR is select ename from emp;
 v_name EMP.ENAME%TYPE;
BEGIN
  OPEN V_CUR;
  FETCH V_CUR INTO v_name;
  while V_CUR%FOUND LOOP
  dbms_output.put_line(v_name);
  FETCH V_CUR INTO v_name;
END LOOP;
close V_CUR;
END;

显示游标

多变量赋值游标

DECLARE 
定义变量1 表.字段%type
定义变量2 表.字段%type
cursor 游标名 is sql语句
BEGIN
OPEN 游标名
loop //循环游标
FETCH 游标名 into 定义变量1,定义变量2//赋值游标
exit when 游标%notfound; //游标未找到 notfound :未找到
操作定义变量1 定义变量2
end loop;
close 游标名; //关闭游标
end;
--------------------
DECLARE
v_id EMP.EMPNO%TYPE;
v_name EMP.ENAME%TYPE;
cursor v_cur is select EMPNO,ENAME from EMP;//查询2个字段
BEGIN
open v_cur;
loop
 FETCH v_cur into v_id,v_name;
 exit when v_cur%notfound;
 dbms_output.put_line(v_id|| '  '|| v_name);
end loop;
close v_cur;
end;

多变量赋值游标

loop显示游标

--loop游标
DECLARE
v_name EMP.ENAME%TYPE;
cursor v_cur is select ENAME from EMP;
BEGIN
open v_cur;
loop
FETCH v_cur into v_name;
exit when v_cur%notfound;
dbms_output.put_line(v_name);
end loop;
close v_cur;
end;

for显示游标

DECLARE
CURSOR 游标名 is sql语句;
BEGIN
FOR 变量 in 游标名 loop
操作 输出游标:变量.字段
end loop;
end;
----------------------------------------
-- for显式游标(指定字段)
DECLARE
cursor v_cur is select EMPNO,ENAME from EMP;
BEGIN
for c in v_cur loop
dbms_output.put_line(c.EMPNO||'  '|| c.ENAME);
END loop;
end;

-- for 显式游标(整个表)
DECLARE
cursor v_cur is select * from EMP;
BEGIN
for c in v_cur loop
dbms_output.put_line(c.EMPNO||'  '|| c.ENAME ||'  '|| c.JOB);
END loop;
end;

for显示游标1

for显示游标2

游标更新行

--使用current of 时 sql语句需要加上 for update
DECLARE
变量1 表.字段%type
cursor 游标名 is sql语句 for update
BEGIN
OPEN 游标名 //打开游标
loop
FETCH 游标名 into 变量1
exit when 游标名%notfound; //游标未找到退出
sql更新语句 where current of 游标名 current of:当前游标
end loop
close 游标名;//关闭游标
--------------------
-- 使用游标更新行
  --调整工资
DECLARE
v_SAL EMP.SAL%TYPE;
cursor v_cur is select SAL from EMP for UPDATE;
BEGIN
open v_cur;
loop
 FETCH v_cur into v_SAL;
 exit when v_cur%notfound;
 UPDATE emp set sal = v_SAL*1.1 where CURRENT of v_cur;
end loop;
close v_cur;
end;

隐式游标

编号属性描述
1%FOUND如果INSERT,UPDATE或DELETE语句影响一行或多行,或老兄SELECT INTO语句返回一行或多行,则返回TRUE,否则返回FALSE。
2%NOTFOUND与%FOUND的逻辑相反。 如果INSERT,UPDATE或DELETE语句没有影响任何行,或SELECT INTO语句未返回任何行,则返回TRUE。 否则返回FALSE。
3%ISOPEN由于Oracle在执行关联的SQL语句后会自动关闭SQL游标,因此总是为隐式游标返回FALSE。
4%ROWCOUNT返回受INSERT,UPDATE或DELETE语句,或者受SELECT INTO语句影响的行数。
BEGIN
SQL语句
IF sql%notfound then
操作
end if;
end;
---------
--隐式游标
BEGIN
UPDATE EMP SET SAL=900 WHERE EMPNO=7309;
IF SQL%NOTFOUND THEN
DBMS_OUTPUT.PUT_LINE('没有找到!');
END if;
END;

隐式游标1

隐式游标 影响行数

BEGIN
SQL语句
操作输出行 sql%rowcount;
end;
------
--隐式游标 影响行数
BEGIN
UPDATE EMP SET SAL=900 WHERE ROWNUM<=5;
DBMS_OUTPUT.PUT_LINE('行'|| SQL%rowcount);
END;

隐式游标

游标案列

/*
用普通游标 和 for 游标
<=1000    +10%
1000-2000 +5%
>2000     +1%
*/

--普通游标 
DECLARE
v_sal EMP.SAL%type;
cursor c_upsal is select SAL from EMP for UPDATE;
v_cny number(3,2);
BEGIN
open c_upsal;
loop
 FETCH c_upsal into v_sal;
 exit when c_upsal%notfound;
 if v_sal<=1000 THEN
 v_cny:=0.1;
 ELSIF v_sal>1000 and v_sal<2000 THEN 
 v_cny:=0.05;
 ELSIF v_sal>2000 THEN
 v_cny:=0.01;
END if;
UPDATE emp set sal=v_sal*v_cny where CURRENT of c_upsal;
end loop;
close c_upsal;
END;



--for游标
DECLARE
cursor c_upsal is select SAL from EMP for UPDATE;
v_cny number(3,2);
BEGIN
for sa in c_upsal loop
if sa.SAL<=1000 THEN
v_cny:=0.1;
ELSIF sa.SAL>1000 and sa.SAL<2000 THEN 
 v_cny:=0.05;
ELSIF sa.SAL>2000 THEN
 v_cny:=0.01;
END if;
UPDATE emp set sal=sa.SAL*v_cny where CURRENT of c_upsal;
END LOOP;
END;

异常处理

异常Oracle错误代码SQLCODE描述
ACCESS_INTO_NULL06530-6530当一个空对象被自动分配一个值时会引发它。
CASE_NOT_FOUND06592-6592当没有选择CASE语句的WHEN子句中的任何选项时,会引发这个错误,并且没有ELSE子句。
COLLECTION_IS_NULL06531-6531当程序尝试将EXISTS以外的集合方法应用于未初始化的嵌套表或varray时,或程序尝试将值分配给未初始化的嵌套表或varray的元素时,会引发此问题。
DUP_VAL_ON_INDEX00001-1当尝试将重复值存储在具有唯一索引的列中时引发此错误。
INVALID_CURSOR01001-1001当尝试进行不允许的游标操作(例如关闭未打开的游标)时会引发此错误。
INVALID_NUMBER01722-1722当字符串转换为数字时失败,因为字符串不代表有效的数字。
LOGIN_DENIED01017-1017当程序尝试使用无效的用户名或密码登录到数据库时引发。
NO_DATA_FOUND01403+100当SELECT INTO语句不返回任何行时会引发它。
NOT_LOGGED_ON01012-1012当数据库调用没有连接到数据库时引发。
PROGRAM_ERROR06501-6501当PL/SQL遇到内部问题时会引发。
ROWTYPE_MISMATCH06504-6504当游标在具有不兼容数据类型的变量中获取值时引发。
SELF_IS_NULL30625-30625当调用成员方法时引发,但对象类型的实例未初始化。
STORAGE_ERROR06500-6500当PL/SQL用尽内存或内存已损坏时引发。
TOO_MANY_ROWS01422-1422当SELECT INTO语句返回多行时引发。
VALUE_ERROR06502-6502当发生算术,转换,截断或者sizeconstraint错误时引发。
ZERO_DIVIDE014761476当尝试将数字除以零时引发。

一个异常

DECLARE
BEGIN
操作
EXCEPTION
when 异常名 then
操作
end;
--------
DECLARE

BEGIN
UPDATE LOLGAME set PRICE=PRICE-1000 where id=3;
EXCEPTION
WHEN others then
dbms_output.put_line('价格必须在0-800!');
END;

多个异常

DECLARE
变量
begin
操作
exception
when 异常名 then
操作
when 异常名 then
操作
....
end;
------
DECLARE
V_NAME LOLGAME.NICKNAME%TYPE;
BEGIN
SELECT NICKNAME INTO V_NAME FROM LOLGAME WHERE ID=100;
DBMS_OUTPUT.PUT_LINE('NMAE:'||V_NAME);
EXCEPTION
WHEN NO_DATA_FOUND THEN
DBMS_OUTPUT.PUT_LINE('数据未找到!');
WHEN others THEN
DBMS_OUTPUT.PUT_LINE('异常');
END;

自定义异常

DECLARE 
定义异常名 exception
变量 类型
BEGIN
操作
....
exception
when 定义的异常名 then
操作

--------
--自定义异常
DECLARE
age_excption EXCEPTION;
age INTEGER;
BEGIN
age:=130;
if age > 120 THEN
raise age_excption;
ELSE
dbms_output.put_line('年龄:'||age);
END IF;
EXCEPTION
WHEN age_excption then
dbms_output.put_line('年龄不能大于120!');
END;

转账

--A转1000到B
DECLARE
transfer EXCEPTION;
Amoney LOLGAME.PRICE%TYPE;
BEGIN
select PRICE INTO Amoney from LOLGAME where ID=3;
if Amoney<1000 THEN
raise transfer;
ELSE
UPDATE LOLGAME set PRICE=PRICE-1000 where ID=3;
update LOLGAME set PRICE=PRICE+1000 where ID=2;
dbms_output.put_line('转账成功!');
END IF;
EXCEPTION
WHEN transfer then
dbms_output.put_line('金额不足 转账失败!');
END;

存储过程

定义储存过程

create procedure 过程名 (变量 类型)
as
定义变量
begin
操作
exception
when 异常名 then
操作

--储存过程
CREATE PROCEDURE find_emp(no INTEGER)
as
--定义变量
v_name EMP.ENAME%TYPE;
BEGIN
select ENAME into v_name FROM EMP WHERE EMPNO=no;
dbms_output.put_line('姓名:'||v_name);
EXCEPTION 
when no_data_found THEN
dbms_output.put_line('没有该人员!');
END;

执行储存器

call 过程名() 有参数则传参数
--执行函数
call find_emp(7369);

out in输入输出

编号参数模式描述
1ININ参数允许将值传递给子程序。它是一个只读参数。在子程序中,IN参数的作用如常数,它不能被赋值。可以将常量,文字,初始化的变量或表达式作为IN参数传递。也可以将其初始化为默认值; 然而,在这种情况下,从子程序调用中省略它。 它是参数传递的默认模式。参数通过引用传递。
2OUTOUT参数返回一个值给调用程序。在子程序中,OUT参数像变量一样。 可以更改其值并在分配该值后引用该值。实际参数必须是可变的,并且通过值传递。
3IN OUTIN OUT参数将初始值传递给子程序,并将更新的值返回给调用者。 它可以分配一个值,该值可以被读取。对应于IN OUT形式参数的实际参数必须是变量,而不是常量或表达式。正式参数必须分配一个值。实际参数(实参)通过值传递。

过程不能在sql语句中运行 函数可以

过程里可以有out in inout参数

函数只能有in参数

--输入输出变量 out输出 IN不用写 out类似返回值
CREATE PROCEDURE Ufunc(nmber INTEGER,nmber2 INTEGER,res OUT INTEGER)
AS
BEGIN
res:=nmber+nmber2;
END;

--测试输入输出
DECLARE
v_res INTEGER;
BEGIN
Ufunc(1,3,v_res);//4
dbms_output.put_line('结果:'||v_res);
END;

函数

create function 函数名 (参数)return 返回类型
as
begin
return 返回内容
end;

--函数
  --定义函数
create FUNCTION hell(name VARCHAR)return VARCHAR
as
BEGIN
return '你好!'||name;
END;

--执行函数
select hell('数据') from dual;

--执行函数
DECLARE
v_na VARCHAR(50);
BEGIN
v_na:=hell('数据包');
dbms_output.put_line('结果:'||v_na);
END;

案例转账过程

--转账过程
CREATE PROCEDURE trans3(user1 INTEGER,user2 INTEGER,money INTEGER)
as
transfer EXCEPTION;
Amoney LOLGAME.PRICE%TYPE;
tranmoer EXCEPTION;
BEGIN
select PRICE INTO Amoney from LOLGAME where ID=user1;
IF Amoney < money THEN
raise transfer;
ELSIF money<=0 THEN
raise tranmoer;
ELSE
update LOLGAME set PRICE=PRICE-money where ID=user1;
UPDATE LOLGAME SET PRICE=PRICE+money WHERE ID=user2;
dbms_output.put_line('转账成功!');
END IF;
EXCEPTION
WHEN no_data_found THEN 
dbms_output.put_line('未找到该用户!');
when tranmoer THEN
dbms_output.put_line('金额不能小于0!');
when transfer THEN
dbms_output.put_line('金额不足 转账失败!');
END;
--测试
call trans3(2,3,1);

触发器

触发器作用

自动生成一些派生列值
强化参照完整性
事件记录和存储表访问信息
审计
表的同步复制
实施安全授权
防止无效的事务

触发器只有在 insert update delete触发

语法

create trigger 触发器名称
{BEFORE | AFTER | INSTEAD OF} // {BEFORE | AFTER | INSTEAD OF} :何时执行触发器; INSTEAD OF 用于视图创建触发器
{insert [or] | update [or] | delete} on 表名
begin
操作
end;

--测试触发器
UPDATE LOLGAME set PRICE=PRICE-1;

语句触发器

只会触发一次 insert or update or delete 更新多行 也触发一次

create trigger 触发器名
after //之后触发 {insert or update or delete }之后触发
{insert [or] | update [or] | delete} on 表名
begin
操作
end

------------------------------
create or REPLACE trigger hell_trgg
after--之后
update on LOLGAME
BEGIN
dbms_output.put_line('触发器成功!');
END;

--测试触发器
UPDATE LOLGAME set PRICE=PRICE-1;

行级触发器

更新一次就触发一次 for each row

create trigger 触发器名
after //之后触发 {insert or update or delete }之后触发
{insert [or] | update [or] | delete} on 表名
for each row
begin
操作
end

------------------------------
create or REPLACE trigger hell_trgg
after--之后
update on LOLGAME
for each row
BEGIN
dbms_output.put_line('触发器成功!');
END;

--测试触发器
UPDATE LOLGAME set PRICE=PRICE-1;

获取新值 旧值

OLDNEW引用不可用于表级触发器,而是可以将它们用于记录级触发器。

如果要在同一个触发器中查询表,则应该使用AFTER关键字,因为触发器只能在应用初始更改并且表返回一致状态后才能查询表或进行更改

使用insert时 旧值为空!

--旧值
:old.字段名

--新值 更新后的
:new.字段名
--触发器 更新多行触发一次是 语句触发器   行级触发器每更新一次都会触发 for each row
create or REPLACE trigger hell_trgg
after--之后
update on LOLGAME
for each row
BEGIN
dbms_output.put_line('触发器成功!');
dbms_output.put_line('结果:'||:OLD.PRICE ||'新:'||:new.PRICE);
END;

--测试触发器
UPDATE LOLGAME set PRICE=PRICE-1;

获取新旧值触发器

触发器案列before

--如果你删除 lolgame的一个用户  触发自动备份到另外一个表
create or replace trigger inc_trgg
before
delete on LOLGAME
for each row
BEGIN
INSERT INTO BAKLOL VALUES(:OLD.ID,:OLD.NICKNAME,:OLD.PRICE,:OLD.BIRTH,:OLD.AREAID);
END;

delete from LOLGAME where ID=3;

select * from BAKLOL;