/*
基本查询
select 列名|* from 表
oracle语法要求严谨 必须有from 表才可以
*/
select emp.* from emp;
select emp.*,1+1 from emp;
select 1+1 from emp
--显示一条记录 去除重复 distinct
select 1+1 from emp where empno = 7369
/*
dual表 虚拟表 没有实际意义 为了补全oracle的语法
*/
select 1+1 from dual
-------------------------------------------
--需求:查询员工编号 员工姓名 员工工作
select empno,ename,job,sal from emp;
--起别名 --
---数字 特殊字符(#$_) 空格必须使用双引号
select empno as "编号",ename "员工姓名",job 工作 from emp;
select empno as "编号",ename "员工姓名",job 工 作 from emp;--空格引起语法错误
select empno as "编!号",ename "员工姓名",job "工 作" from emp;--特殊字符引起语法错误
select empno as "编!号",ename 1234,job "工 作" from emp;--数字引起错误
select empno as 编#号,ename "1234",job "工 作" from emp;
--查询员工的工作-- 关键字 distinct
select distinct job from emp;
--查询员工的年薪
select * from emp;
select sal*12+comm from emp;
--null值参与运算结果为null if comm==null 计算加0
--nvl(v1,v2)v1原始数值 如果v1为null返回v2 v1不为空 返回v1
select sal*12+nvl(comm,0) from emp;
select sal*12+nvl(comm,0) 年薪 from emp;
--列值的拼接 员工编号: 7499 员工姓名: SMITH
--oracle使用concat函数实现列值拼接 --只支持两个参数的拼接
select concat('员工编号:',empno) from emp;
--嵌套实现 多重嵌套很麻烦
select concat(concat('员工编号:',empno),' 员工姓名') from emp;
--java实现方式 员工编号:'+empno+' 员工姓名'
--oracle特有的连接符 ||
select '员工编号:'||empno||' 员工姓名'||ename 个人简介 from emp;
---------------------------------------
/*
select *|列 from 表 where 条件
条件表达式
比较运算 > < = >= <= != <>
逻辑运算 and or not
其余运算
like 模糊查询 % 匹配0个或者多个
_ 占位一个字符
between and 判断区间 包含边界
in not in 判断范围
is null is not null 判断空值
*/
--查询工作不是 MANAGER 的员工信息
select * from emp where job !='MANAGER'
select * from emp where job <>'MANAGER'
--查询员工的工作 是 MANAGER 或者是PRESIDENT的员工信息
select * from emp where job = 'MANAGER' or job = 'PRESIDENT'
--使用逻辑非 not 实现不是MANAGER的员工信息
--JAVA 非的使用 !job.equals("MANAGER")
select * from emp where not job = 'MANAGER'
--查询员工姓名包含M的员工信息
select * from emp where ename like '%M%'
--查询员工姓名第二位为M的员工信息
select * from emp where ename like '_M%'
--查询员工的工资 在 1500----3000之间的员工信息
select * from emp where sal between 1500 and 3000
--查询员工的工作 是 MANAGER 或者是PRESIDENT的员工信息
select * from emp where job in ('MANAGER','PRESIDENT')
--查询有奖金的员工信息
select * from emp where comm is not null and comm !=0
select * from emp where comm > 0
--对数据有特殊的排序要求
/*
order by 列 desc|asc
升序asc 默认
*/
--按照工资做从低到高的排序
select * from emp order by sal
--按照工资做从高到低的排序
select * from emp order by sal desc
--按照奖金从高到低排序
select * from emp order by comm desc
--null的倒叙排序默认在上面 置于末尾使用 nulls last
select * from emp order by comm desc nulls last
/*
函数 数据库提供一些方法支持 数据的查询或者处理
单行函数
针对每一条记录的列值做处理 nvl concat
数值函数
字符函数
日期函数
转换函数
通用函数
多行函数 参数运算的记录为多条 返回结果为一条
聚合函数
五个聚合
count 统计记录数
sum 求和统计
avg 求平均值
max 求最大值
min 求最小值
*/
/*
数值函数 对数值处理的函数
四舍五入 round(v1,v2) v1原始数值 v2是保留的小数位数
数值截取 trunc(v1,v2) v1原始数值 v2是保留的小数位数
不做四舍五入操作 直接舍去数值
求余数 mod(v1,v2) java 10%3 ==1
*/
--43.726四舍五入
select round(43.726) from dual; --默认小数位数为 0 44
select round(43.726,0) from dual;--44
select round(43.726,1) from dual;--43.7
select round(43.726,2) from dual;--43.73
select round(43.726,-1) from dual;-- 40
select round(43.726,-2) from dual;--0
select round(53.726,-2) from dual;--100
--数值截取
select trunc(43.726) from dual; --43
select trunc(43.726,0) from dual;--43
select trunc(43.726,1) from dual;--43.7
select trunc(43.726,2) from dual;--43.72
select trunc(43.726,-1) from dual;-- 40
select trunc(43.726,-2) from dual;--0
select trunc(53.726,-2) from dual;--0
--求余数
select mod(10,3) from dual; ---1
/*
字符函数
获取字符串长度 length()
截取字符 substr(v1,v2,v3) v1原始字符串 v2起始位置 v3截取长度
大小写转换 upper lower
替换字符 replace(v1,v2,v3) v1原始字符串 v2被替换的字符串 v3替换成的字符
替换匹配的所有字符
去除空格 trim() 去除两端的空格
*/
--abcde
select length('abcde') from dual; --5
--截取字符
--从0和1开始都是第一位
select substr('abcde',0,2) from dual;-- ab
select substr('abcde',1,2) from dual;-- ab
select substr('abcde',-1,2) from dual;-- e
select substr('abcde',-2,2) from dual;-- de
--大小写转换
/*
使用场景 忽略数据库中的大小写
xzY3 XZY3 xzy3 xzY3
查询SMITH 的员工信息 smith SMITH smiTH
*/
select * from emp where ename = upper('smith');
select * from emp where ename = upper('SMITH');
select * from emp where ename = upper('smiTH');
--替换字符串
--hello
select replace('hello','l','o') from dual; --heooo
--去除空格 __abc_de_
select trim(' abc de ') from dual;--abc de
select replace(' abc de ',' ','') from dual;
/*
日期函数
获取当前时间 sysdate
给系统时间增加月数 add_months(dataV1,monthV2)
获取两个时间间隔的月数 months_between(dat21,date2)
*/
select sysdate from dual;
--给当前时间增加两个月
/*
ticket 表
id orderNum createTime invalidTime
1 1122333 2018-1-12 2018-4-12
2 1122444 2018-1-12 2018-6-12
select * from ticket where sysdate<invalidTime and invalidTime<add_months(sysdate,1)
*/
select add_months(sysdate,2) from dual;
--查询员工入职到现在多少个月
select months_between(sysdate,hiredate) from emp;
--查询员工入职到现在多少天 日期和日期做计算结果为天数
select round(sysdate-hiredate) from emp;
/*
转换函数
数值互换字符串
日期互换字符串
to_number 转成数值
to_char 转成字符串
to_date 转成日期
*/
select to_number('123') +1 from dual;
select '123' +1 from dual; --数字格式的字符串自动转换
--日期和字符串的转换
select to_char(sysdate,'yyyy-mm-dd') from dual;
select to_char(sysdate,'yyyy') from dual;
select to_char(sysdate,'mm') from dual;
select to_char(sysdate,'dd') from dual;
select to_char(sysdate,'day') from dual; --星期的格式
select to_char(sysdate,'yyyy-mm-dd hh:mi:ss') from dual;--oracle数据库分钟是mi
--字符串转换日期
select to_date('2018-03-19','yyyy-mm-dd') from dual;
select to_date('2018-03-19','yyyy-mm-dd hh:mi:ss') from dual;
--jsp页面取值数据库是年月日 页面显示时分秒会自动显示00:00:00
select to_date('2018-03-19 17:13:33','yyyy-mm-dd hh24:mi:ss') from dual;
--jsp页面的24小时和12小时切换 HH hh
/*
通用函数
nvl()处理空值 ifnull()
ios android
nvl2(v1,v2,v3)v1是原始数值 v2是v1不为空的返回值 v3是v1为空的返回值
处理空值
concat()拼接值
*/
select nvl2(1,2,3) from dual;---2
select nvl2(null,2,3) from dual;---3
/*
聚合函数
特点:忽略null值 列值为空不参与运算
count 统计记录数
sum 求和统计
avg 求平均值
max 求最大值
min 求最小值
**/
--需求统计员工的个数
/*
三种统计 如果表中没有唯一索引 推荐使用后两种
如果存在索引 三种效率一致
*/
select count(*) from emp;
select count(empno) from emp;
select count('abc') from emp;
--使用奖金的列做数量统计
select count(comm) from emp; --4
--查询员工的奖金总和
select sum(comm) from emp; --2200
--查询员工的平均奖金
select avg(comm) from emp; --550
/*
分组统计
group by 列
分组之后的数据 使用having 聚合函数
分组之前的数据 使用where
规则限制 如果group by作为分组,那么select 语句中只能查询 group by后面的列
和其余的聚合函数
*/
--需求:统计每个部门的平均工资
select * from emp
select deptno,avg(sal) from emp group by deptno
--查询部门平均工资>2000的部门编号
select deptno,avg(sal) from emp group by deptno having avg(sal)>2000
--查询部门平均工资 参与部门平均工资运算的员工工资必须大于1500
select deptno,avg(sal) from emp where sal>1500 group by deptno
--统计同一个工作,同一个部门的员工数量
--多列分组 使用多个列值 做分组统计 列值完全一致才会分为一组
select deptno,job, count(*) from emp group by deptno,job
--加入员工的姓名查询
select ename, deptno,job, count(*) from emp group by deptno,job,ename
/*
多表查询 从多张表查询数据 分析数据来源为多张表
*/
--查询员工信息和员工的部门信息 dept
select * from emp;
select * from dept;
--同时查询员工表和部门表 --加入关联条件提取有效数据
select * from emp,dept where emp.deptno=dept.deptno
/*
内连接 隐式内连接 select * from A,B where A.列=B.列
显示内连接 select * from A inner join B on A.列=B.列
查询特点 作为关联查询的表 必须有完全匹配的条件数据 才会提取记录
*/
--使用显式内连接实现
select * from emp inner join dept on emp.deptno=dept.deptno
/*
外连接 左外连接 select * from A left join B on A.列=B.列
特点:以左表为基准,左表数据要全部显示,右表数据
作为补充显示 没有匹配的数据 显示为null
右外连接 select * from B right join A on A.列=B.列
特点:以右表为基准,右表数据要全部显示,左表数据
作为补充显示 没有匹配的数据 显示为null
*/
--需求:查询部门信息 和部门的员工信息 没有员工的部门信息也要显示
--左外连接
select * from dept left join emp on dept.deptno = emp.deptno
--右外连接
select * from emp right join dept on dept.deptno = emp.deptno
--强制要求dept列值显示在左
select dept.*,emp.* from emp right join dept on dept.deptno = emp.deptno
/*
oracle特有外连接 (+)
根据需求将符号(+)放在作为补充显示的表的列后面
select * from A,B where A.列(+)=B.列
*/
select * from emp inner join dept on emp.deptno(+)=dept.deptno
/*
自连接 自己跟自己做关联查询 为了区分两个表 必须起别名
select * from A A1,A A2 where A1.列=A2.列
使用场景: 查询的数据来源为同一张表
*/
--查询员工的信息 和员工的领导信息
select * from emp e,emp m where e.mgr = m.empno
--需求:查询员工编号 员工姓名,员工的 领导编号,领导姓名,员工的部门名称
--1.定义查询数据 员工信息 领导信息 部门信息
--2.定义数据来源 emp emp dept
--3.分析关联表和关联条件
select e.empno,e.ename,m.empno mgr_no,m.ename mgr_name ,d.dname
from emp e,emp m ,dept d
where e.mgr = m.empno and e.deptno = d.deptno
--再上面基础之上,再查询员工的工资等级 salgrade
select * from salgrade
select e.empno,e.ename,s1.grade,d.dname,
m.empno mgr_no,m.ename mgr_name
from emp e,emp m ,dept d,salgrade s1
where e.mgr = m.empno and e.deptno = d.deptno
and e.sal between s1.losal and s1.hisal
--再上面基础之上 再查询领导的工资等级
select e.empno,
e.ename,
s1.grade,
d.dname,
m.empno mgr_no,
m.ename mgr_name,
s2.grade
from emp e, emp m, dept d, salgrade s1, salgrade s2
where e.mgr = m.empno
and e.deptno = d.deptno
and e.sal between s1.losal and s1.hisal
and m.sal between s2.losal and s2.hisal
/*
订单查询 火车票
订单号 订单的时间 订单的总价钱 ---订单表
列车班次 发车时间 --列车表
购票的用户信息 --用户表
乘客信息 --乘客表
支付的信息 --支付表
联系人信息 --联系人表
*/
/*
子查询:在查询语句中可以嵌套查询语句不限制一条
语法: 单行子查询 select * from A where A.列 = (sql语句返回唯一的一个值)
多行子查询 select * from A where A.列 in (sql语句返回单列多值)
select * from A,(sql语句得到临时表) T where A.列=T.列
*/
--范例:查询比员工7654工资高,同时从事和7788相同工作的员工信息?
--1.员工信息
--2.emp表
--3.查询条件 sal>7654的工资 and job=7788的工作
--先查询7654的工资 和7788的工作
select sal from emp where empno=7654 --1250
select job from emp where empno=7788 --ANALYST
select * from emp where sal >1250 and job = 'ANALYST'
--使用sql语句替换查询条件
select * from emp where
sal >(select sal from emp where empno=7654)
and job = (select job from emp where empno=7788)
--范例:查询每个部门的最低工资,和最低工资的员工信息及员工的部门名称
--1.部门最低工资 员工信息 部门名称
--得到部门最低工资的数据来源
select deptno,min(sal) d_min from emp group by deptno
--2.sql临时表,emp,dept
--3.关联条件
select e.empno,e.ename,e.sal,e.deptno,d_m.d_min,d.dname from emp e,
(select deptno,min(sal) d_min from emp group by deptno) d_m,
dept d
where e.deptno = d_m.deptno and e.sal = d_m.d_min
and e.deptno = d.deptno
--查询不是领导的员工信息
--1.员工信息
--2.emp
--3.条件 不是领导
/*
数据查询 先判断条件成立 提取数据
null值的判断只能是 is 判断 其余表达式 UNKONW
*/
select * from emp
where empno not in( select mgr from emp where mgr is not null)
select min(sal) d_min from emp group by deptno
--子查询错误示例
select * from emp
where sal = (select min(sal) d_min from emp group by deptno)
---只要员工的工资是 800 950 1300 都会提取
select * from emp
where sal in (select min(sal) d_min from emp group by deptno)
/*
exists 存在
判断sql语句是否存在 exists(sql) 如果sql结果集存在 表达式true
结果集不存在 表达式false
子查询执行顺序 先走括号内子查询语句 得到结果用于主查询判断
exists如果作为子查询 子查询语句关联主查询的表列值,那么执行顺序发生更改
先走主查询,得到主查询的一条记录,判断子查询是否成立,如果成立,返回当前的
主查询记录
使用场景:如果主查询的记录结果集比子查询的表中多 推荐使用 in
如果子查询的记录结果集比主查询的多 推荐使用 exists
先走的查询语句 记录少,效率高
*/
--exists的简单示例
select * from emp where exists(select * from dept)--emp的所有记录
select * from emp where exists(select * from dept where deptno=1234) --没有结果
--查询有员工的部门信息
--使用之前学过的方式 实现
--1.部门信息
--2.部门表 dept
--3.条件 部门有员工
select * from dept where deptno in ( select deptno from emp)
--使用exists实现
select * from dept where
exists(select * from emp where emp.deptno=dept.deptno)
/*
分页效果实现 mySql 使用limit 0 3
需求:提取5--10条记录
oracle使用 rownum 是一个伪列,查询数据时候才会产生一系列数值 1 2 3 4
作用是实现分页的 必须借助于rownum 必须使用子查询
*/
--rowNum的示例
select rownum,emp.* from emp;
--提取前三条
select rownum,emp.* from emp where rownum < 4
--提取五条以后的数据
select rownum,emp.* from emp where rownum > 5
--先查询生成rownum 再用于条件过滤判断
select * from (select rownum r,emp.* from emp) t where t.r>5 and t.r<11
--分页优化结果
select * from (select rownum r,emp.* from emp where rownum < 11) t where t.r>5
--找到员工表中工资最高的前三名
--1.先按照工资倒序排序
select * from emp order by sal desc
--2.加入rownum 先生成rownum 按照工资排序 顺序错乱
select rownum,emp.* from emp order by sal desc
--3.先排好顺序,再查询生成rownum
select rownum,t.* from (select * from emp order by sal desc)t
--4.提取前三条数据
select rownum,t.*
from (select * from emp order by sal desc)t where rownum<4
/*
rowid 指的是数据库在保存记录的时候,生成的真实物理地址 唯一不变
用于数据库操作记录使用
rownum 查询才会生成,而且根据条件筛选 排序规则发生变化 用于分页使用
*/
select * from emp;
select rowid,emp.* from emp;
--找到员工表中薪水大于本部门平均薪水的员工信息。
--1.部门平均工资 员工的信息
select deptno,avg(sal) d_avg from emp group by deptno
--2. 临时表 emp
--3.工资大于本部门平均工资的员工
select * from emp ,
(select deptno,avg(sal) d_avg from emp group by deptno) d_a
where emp.deptno = d_a.deptno and emp.sal >d_a.d_avg
/*
条件表达式的使用
sql语句数据库通用的表达式
case 列
when 列值1 then 处理语句
when 列值2 then 处理语句
when 列值3 then 处理语句
else
默认处理
end
--oracle数据库条件表达式 decode(列,列值1,显示值1,列值1,显示值1,默认值)
*/
---使用条件表达式实现 员工等级的显示 如果1 显示一级
select e.empno,e.ename,
case s1.grade
when 1 then '一级'
when 2 then '二级'
when 3 then '三级'
else
'四级'
end
,
d.dname,
m.empno mgr_no,m.ename mgr_name
from emp e,emp m ,dept d,salgrade s1
where e.mgr = m.empno and e.deptno = d.deptno
and e.sal between s1.losal and s1.hisal
---使用docode函数实现
select e.empno,e.ename,
decode(s1.grade,1,'一级',2,'二级',3,'三级','四级') 等级
,
d.dname,
m.empno mgr_no,m.ename mgr_name
from emp e,emp m ,dept d,salgrade s1
where e.mgr = m.empno and e.deptno = d.deptno
and e.sal between s1.losal and s1.hisal
--统计每年入职的员工个数
select * from emp;
select to_char(emp.hiredate,'yyyy') hire_year,count(1) hire_count
from emp group by to_char(emp.hiredate,'yyyy')
--1.使用条件表达式 处理结果尝试竖起来一列
select decode(t.hire_year,'1987',t.hire_count) "1987" from
(select to_char(emp.hiredate,'yyyy') hire_year,count(1) hire_count
from emp group by to_char(emp.hiredate,'yyyy')) t
--2.使用聚合函数忽略null值的记录
select sum(decode(t.hire_year,'1987',t.hire_count)) "1987" from
(select to_char(emp.hiredate,'yyyy') hire_year,count(1) hire_count
from emp group by to_char(emp.hiredate,'yyyy')) t
--3.使用聚合函数补全其余的列
select sum(decode(t.hire_year,'1980',t.hire_count)) "1980",
sum(decode(t.hire_year,'1981',t.hire_count)) "1981",
sum(decode(t.hire_year,'1982',t.hire_count)) "1982",
sum(decode(t.hire_year,'1987',t.hire_count)) "1987"
from
(select to_char(emp.hiredate,'yyyy') hire_year,count(1) hire_count
from emp group by to_char(emp.hiredate,'yyyy')) t
--4.使用sum求和运算补全total
select sum(t.hire_count) total,
avg(decode(t.hire_year,'1980',t.hire_count)) "1980",
max(decode(t.hire_year,'1981',t.hire_count)) "1981",
min(decode(t.hire_year,'1982',t.hire_count)) "1982",
sum(decode(t.hire_year,'1987',t.hire_count)) "1987"
from
(select to_char(emp.hiredate,'yyyy') hire_year,count(1) hire_count
from emp group by to_char(emp.hiredate,'yyyy')) t
/*
集合的运算
交集 取两个集合共同的部分 intersect A(1,2,3) B(2,3,4) A交B (2,3)
并集 取两个集合最大的范围 union A(1,2,3) B(2,3,4) A并B (1,2,3,4)
包含重复数据的合并 union all A(1,2,3) B(2,3,4) A并B (1,2,3,2,3,4)
差集 从一个集合去掉另外一个集合剩余的部分 minus A(1,2,3) B(2,3,4) A差B (1)
使用场景:
跨表的数据合并
规则限制 列的数量一致 类型一致
*/
--范例:工资大于1500,或者是20部门下的员工
select * from emp where sal>1500 or deptno=20
--使用集合实现
select * from emp where sal>1500
union
select * from emp where deptno=20
--合并包含重复的
select * from emp where sal>1500
union all
select * from emp where deptno=20
--范例:工资大于1500,并且是20部门下的员工
select * from emp where sal>1500 and deptno=20
--使用集合
select * from emp where sal>1500
intersect
select * from emp where deptno=20
--范例:1981年入职的普通员工(不包括经理,总裁)
--使用之前的方式实现
select * from emp where to_char(hiredate,'yyyy')='1981' and
job not in ('PRESIDENT','MANAGER')
--使用集合实现
select * from emp where to_char(hiredate,'yyyy')='1981'
minus
select * from emp where job in ('PRESIDENT','MANAGER')
--合并员工的数据和领导的数据
select empno,ename from emp
union
select mid,mname from manager
--类型不匹配合并失败
select ename,empno from emp
union
select mid,mname from manager
---查询公司的所有员工 编号 姓名 工作
select empno,ename,job from emp
union
select mid,mname,'manager' from manager
--创建一个 manager表 作为公司的领导表
create table manager(
mid number(9),
mname varchar(11)
)
insert into manager values(1,'zs');
insert into manager values(2,'ls');
commit;
/*
DDL语句 数据定义语言 使用sql语句创建管理数据库的对象
表空间 实例分配的一块空间 用于项目开发 建表和插入数据
创建语法:
create tablespace 表空间名
datafile '物理文件路径'
size 初始化大小
autoextend on
next 扩展大小
*/
---创建表空间示例--管理员才能创建
create tablespace sinosoft
datafile 'c:\sinosoft.dbf'
size 100m
autoextend on
next 10m
---操作表空间 建表和插入数据 管理员创建用户
create user sinosoft
identified by sinosoft
default tablespace s inosoft
--对用户授权
/*
授权语法:
grant 权限 to 用户
权限分类: connect 最基本的权限
resource 比较高级权限
dba 最高级权限 相当于管理员
*/
--管理员授予用户 connect 权限
grant connect to itheima_310
--管理员授予itheima dba最高级权限
grant dba to itheima_310
--建表测试
/*
create table 表名(
列名 列的数据类型
)
*/
/*
oracle数据库表 根据表空间划分
同一个表空间 表根据用户划分
*/
create table p(
pid number(9),
pname varchar(10)
)
/*
设计表的步骤
1.表中设计的列 练习自己定义
2.列的数据类型
数值类型 int long short bigint tinyint double float
oracle number(v1,v2) 数值类型 v1是数值总长度
v2是数值的小数位数
v1默认不写 32位长度
v2默认不写 0 取整数
number(6,2) ---9999.99
字符类型
char 固定长度的字符类型 char(10) 存储 'zs'
实际2个长度 占用空间10个长度
varchar
可变长度的字符类型 varchar(10) 存储 'zs'
实际2个长度 占用空间2个长度
varchar2
可变长度的字符类型 varchar(10) 存储 'zs'
实际2个长度 占用空间2个长度
日期类型
mySql的日期格式
date格式 存储的日期为 yyyy-mm-dd
datetime格式 存储的日期为 yyyy-mm-dd hh:mi:ss
timestamp 默认存储秒后3位毫秒
oracle日期格式
date格式 存储的日期为 yyyy-mm-dd hh:mi:ss
timestamp 更精确的日期类型 精确到秒后9位 纳秒
大文本类型
clob 字符类型大文本 4G的长度
blob 二进制类型大文本 4G的长度
long 长文本 2G的长度
3.约束
主键约束 primary key
外键约束 foreign key
非空约束 not null
唯一约束 unique
检查约束 check(gender in (1,0))--判断列值是否满足表达式
--自定义约束名
constraint 约束名 约束类型(列名)
*/
--创建person表 id 姓名 电话 性别
create table person(
pid number(9),
pname varchar2(11) not null,
phone varchar2(11) unique,
gender number(1) check(gender in (0,1)),
constraint pk_person_pid primary key(pid)
)
--插入数据测试约束
--oracle的事务需要手动选择提交或者回滚
insert into person values(1,'zs','11122223333',1);
insert into person values(1,'zs','11122223333',1);--违反主键约束
insert into person values(2,'zs','11122223333',1);--违反唯一约束
insert into person values(2,'zs','11122224444',1);
insert into person values(2,null,'11122224444',1);--违反非空约束
insert into person values(2,'','11122224444',1); --空串当作null处理
insert into person values(3,'xiaofang','11122225555',9); --违反检查约束
insert into person values(3,'xiaofang','11122225555',0);
commit;
/*
修改表结构
alter table 表名
增加一列 add(列名 数据类型)
修改列数据类型 modify(列名 数据类型)
重命名列 rename column 旧列名 to 新列名
删除一列 drop column 列名
增加约束 add constraint 约束名 约束类型(列名)
*/
--新增用户的地址列 address
alter table person add(address varchar2(100))
--修改列的数据类型 address 改成 char 类型 40个长度
alter table person modify(address char(40))
alter table person modify(pname number(10))--更改类型保证为空
--更改性别的gender 改成sex
alter table person rename column gender to sex
--删除address列
alter table person drop column address
--增加p表的主键约束
alter table p add constraint pk_p_pid primary key(pid)
/*
DML语句 数据操纵语言 对表中数据做操作
插入数据 insert into 表名 values(.....)
insert into person(pid,pname,phone) values(2,'zs','11122224444');
---指定列名插入特定的列值
修改数据
update 表名 set 列名 = 值 where 条件
删除数据
delete from 表名 where 条件
delete from 表名 一条条删除 效率略低
truncate table 表名 摧毁表结构 重建表结构 效率高
*/
--需求:使用scott用户下的emp表做练习
select * from scott.emp;
--自己创建emp表 数据同scott表的数据完全一致
create table emp as select * from scott.emp;
--修改SMITH的工资 涨100块钱
update emp set sal =sal+100 where ename='SMITH';
commit;
/*
在存在主外键的情况下 删除主表的记录
开发规范:数据库表数据不允许物理删除 逻辑删除
1.先删除子表记录,再删除主表记录
2.设置外键为null
3.级联删除 删除主表记录的同时 ,把子表记录删除
java类的关联属性上 CASCADE.ALL
数据库在关联的列上做设置 级联删除 外键使用 on delete cascade 实现
4.强制删除主表
*/
--创建主表和从表
create table orders(
oid number(9) primary key ,
oname varchar2(15) ,
oprice number(6,2)
)
create table order_detail(
detail_id number(9) primary key,
detail_name varchar2(15),
detail_price number(6,2),
oid number(9),
constraint fk_detail_oid foreign key(oid) references orders(oid)
-- on delete cascade
)
---插入主表和从表的记录
insert into orders values(1,'订单1',1000.00);
insert into order_detail values(1,'订单1',1000.00,1);
commit;
------查看两张表的数据
select * from orders;
select * from order_detail;
insert into order_detail values(2,'订单1',1000.00,2);--违反外键约束
commit;
--删除主表记录测试
delete from order_detail where detail_id =1;
commit;
delete from orders where oid = 1;
commit;
--直接删除主表 cascade constraint --不推荐使用
drop table orders cascade constraint --删除了关联的约束
/*
事务 作为一个逻辑操作单元 执行的任务全部成功,全部失败
ACID 原子性 一致性 隔离性 持久性
没有隔离级别 脏读 幻读 不可重复读
事务的隔离级别
oracle 只有三种 READ COMMITED 默认级别
SERIALIZABLE 串行化
READ ONLY 只读
事务的保存点:
为了保证执行成功的任务 正常提交
声明事务保存点 savepoint 保存点名;
出现异常 回滚到保存点 rollback to 保存点
继续提交 commit;
*/
---保存点的示例
declare
begin
insert into orders values(1,'订单1',1000.00);
insert into orders values(2,'订单1',1000.00);
insert into orders values(3,'订单1',1000.00);
insert into orders values(4,'订单1',1000.00);
insert into orders values(5,'订单1',1000.00);
savepoint s1;--声明保存点 保存之前的任务
insert into orders values(6,'订单1',1000.00);
insert into order_detail values(1,'订单1',1000.00,100);--执行失败
commit;
exception
when others then
rollback to s1; --发生异常任务回滚
commit;
end;
/*
数据库的其余对象
视图
是一个虚拟表 不存储数据 只支持数据查询,数据来源为原始表
意义:为了数据的安全
为了权限的细分
作用:简化查询的sql语句
提高查询效率
数据不会经常变化 放到缓存可以
create view 视图名 as select 列 from 表
序列
索引
同义词
*/
--查询员工的信息 创建视图支持部分数据查询
create view emp_view as select empno,ename,job,deptno from emp;
--查询视图的数据
select * from emp_view;
--修改视图的数据
update emp_view set ename='SSSS' where ename='SMITH';
commit;
--创建只读的视图 支持查询
create view e_view as select empno,ename,job,deptno from emp with read only
update e_view set ename='SMITH' where ename='SSSS';
commit;
/*
序列 数据库生成的一系列数值 1 2 3 4
用于实现 主键 自增 mySql设置主键自增 auto_increment
oracle的自增长 必须借助于序列实现
创建序列
create sequence 序列名
属性:
currval ---当前值 序列目前生成的值
nextval ---下一个值 序列下一个生成的值
同样一条sql语句 不管nextval调用多少次 都是一个值
*/
--创建序列
create sequence order_sequence
--查询序列的两个属性
select order_sequence.currval from dual;--必须nextval调用才支持查询
select order_sequence.nextval from dual;--默认值从1开始生成 默认按照1自增
--插入数据使用序列实现自增长
insert into orders values(order_sequence.nextval,'订单1',1000.00);
commit;
/*
索引 看作一本书的目录 没有目录找固定的章节
挨页查看 效率低
用于提升数据检索速度 数据量大使用
创建索引
create index 索引名 on 表名(列)
复合索引
create index 索引名 on 表名(列1,列2)
使用通用规范 如果能使用多列索引 建议使用
多列索引会高于单列索引
*/
--测试索引的效果
--1.创建大数据量的表 5000000条记录
declare
begin
for i in 1..5000000 loop
insert into orders values(order_sequence.nextval,'订单'||order_sequence.nextval,1000.00);
end loop;
commit;
end;
--2.先查询没有索引 记录耗时
select * from orders where oname = '订单2222222' ---3.265
--3.创建索引
create index order_index on orders(oname)
--4.查询同样的条件 记录耗时
select * from orders where oname = '订单3333333'--0.063
--创建多列索引
create index order_fu_index on orders(oname,oprice)
--查询订单姓名和定价价钱
select * from orders where oname = '订单3333333' and oprice=1000.00 --0.063
select * from orders where oid=3333333
select 3.265/0.063 from dual;
/*
同义词 给用户的对象起别名
create synonym 同义词名 for 用户.对象
*/
create synonym dept_syn for scott.dept
select * from dept_syn
/*
数据的导入和导出
导出目的 备份数据
导入目的 还原数据
数据库整体迁移--专业数据库管理员
实现方式
命令行导入导出 必须安装数据库服务端
导出命令
exp 整个数据库导出 exp 用户名/密码 file='导出文件.dmp' full=y
按照用户导出 exp 用户名/密码 owner=用户名 file='导出文件.dmp'
按照表名导出 exp 用户名/密码 file='导出文件.dmp' tables=表名,表名2
imp 导入 更换exp为imp
图形化工具导入导出
tools --export user object --只能导出表结构 不能备份表数据
可以导出所有用户对象
--export tables
oracle导出 --必须安装数据库服务端
sql文件导出 --导出的文件为sql文件 导出的时候勾选create table
plsql导出 --导出的文件文件pde格式 导入数据勾选 create table
*/
/*
PLSQL 编程语句 procedure language 过程语言 在sql语句中加入处理过程的
语句 常见的条件判断 循环结构
基本结构
declare
--声明部分
--定义变量的位置
begin
--实现业务逻辑的代码块
end;
*/
---plSql简单示例
declare
v_n number(8) :=1; --定义数值类型的变量
v_s varchar2(10) :='s'; --定义字符类型的变量
begin
dbms_output.put_line('v_n===='||v_n);--输出语句相当于system.out.println();
dbms_output.put_line('v_s===='||v_s);
end;
--查询员工7654的工资 判断工资的数值 输出语句
/*
条件表达式 if的语法
if .. then ..
elsif .. then..
else
..
end if; --表达式结束
*/
declare
emp_sal number;
e_sal emp.sal%type; --引用类型变量
emp_row emp%rowtype; --记录类型变量
begin
select sal into e_sal from emp where empno=7654;--查询赋值使用into
dbms_output.put_line('e_sal===='||e_sal);
select * into emp_row from emp where empno=7654;
if emp_row.sal > 3000 then
dbms_output.put_line('工资大于3000==='||emp_row.sal);
elsif emp_row.sal < 1000 then
dbms_output.put_line('工资小于1000==='||emp_row.sal);
else
dbms_output.put_line('工资位于1000----3000==='||emp_row.sal);
end if;
end;
---------------------------------------------
/*
循环结构 java循环结构
for(){} while(){} do{}while()
-------------
loop
exit when 条件
end loop
----------------
while 条件 loop
end loop;
------------------
for 变量 in 范围 loop
end loop;
*/
---使用循环语句输出1----10的数字
declare
v_n number :=1;
begin
loop
exit when v_n>10;
dbms_output.put_line(v_n);
v_n := v_n+1;
end loop;
end;
----------
declare
v_n number :=1;
begin
while v_n<11 loop
dbms_output.put_line(v_n);
v_n := v_n+1;
end loop;
end;
----for循环---for(Customer c:list){}
declare
begin
for v_n in 1..10 loop
dbms_output.put_line(v_n);
end loop;
end;
/*
游标 光标
用于接收查询得到的记录结果集 ResultSet 需要提取 rs.next()
声明游标 cursor 游标名 is select * from 表名
打开游标 open 游标名
提取游标 fetch 游标名 into 记录类型变量
关闭游标 close 游标名
游标的属性:
%notfound 没找到
%found 找到
*/
declare
cursor emp_cursor is select * from emp; --查询所有员工赋值给游标
emp_row emp%rowtype;--声明记录类型变量 用于接收游标的提取
begin
open emp_cursor; --打开游标
if emp_cursor%found then
dbms_output.put_line('found');
elsif emp_cursor%notfound then
dbms_output.put_line('notfound');
elsif emp_cursor%found is null then
dbms_output.put_line('null');
end if;
--游标的属性 先提取 再判断使用
fetch emp_cursor into emp_row;
while emp_cursor%found loop --没满足条件
dbms_output.put_line('empno=='||emp_row.empno||'==ename=='||emp_row.ename);
fetch emp_cursor into emp_row;
end loop;
close emp_cursor;
end;
--loop循环提取游标
declare
cursor emp_cursor is select * from emp; --查询所有员工赋值给游标
emp_row emp%rowtype;--声明记录类型变量 用于接收游标的提取
begin
open emp_cursor; --打开游标
loop
fetch emp_cursor into emp_row;
exit when emp_cursor%notfound;
dbms_output.put_line('empno=='||emp_row.empno||'==ename=='||emp_row.ename);
end loop;
close emp_cursor;
end;
--需求:带参数游标提取某个部门的员工记录
declare
cursor emp_cursor(dno number) is select * from emp where deptno =dno; --查询所有员工赋值给游标
emp_row emp%rowtype;--声明记录类型变量 用于接收游标的提取
begin
open emp_cursor(10); --打开游标
loop
fetch emp_cursor into emp_row;
exit when emp_cursor%notfound;
dbms_output.put_line('empno=='||emp_row.empno||'==ename=='||emp_row.ename);
end loop;
close emp_cursor;
end;
/*
系统引用游标
emp_cursor sys_refcursor;--声明变量类型为系统引用游标 不需要给游标指定结果集
open emp_cursor for select * from 表
*/
--使用系统引用游标查询员工的记录结果集
declare
emp_cursor sys_refcursor;--声明变量类型为系统引用游标 不需要给游标指定结果集
emp_row emp%rowtype;--声明记录类型变量 用于接收游标的提取
begin
open emp_cursor for select * from emp;
loop
fetch emp_cursor into emp_row;
exit when emp_cursor%notfound;
dbms_output.put_line('empno=='||emp_row.empno||'==ename=='||emp_row.ename);
end loop;
close emp_cursor;
end;
/*
例外 异常
分类:运行时异常 编译时异常 系统定义好的异常类型
自定义异常 new 自定义类 继承 Exception
抛出自定义异常 赋值错误代码 提示语句
使用场景: 业务场景不符合规则
异常处理 try{}catch(IndexOutOfBoundException e){}catch(Exception e){}
exception --处理异常的代码块
when 异常类型 then 异常处理
when 异常类型 then 异常处理
*/
--除数为0的异常
declare
v_n number :=1;
v_m number :=0;
begin
v_n:=v_n/v_m;
exception
when zero_divide then
dbms_output.put_line('除数不能为0');
end;
--赋值错误异常
declare
v_n number :=1;
v_m number :=0;
begin
v_n:='ss';
v_n:=v_n/v_m;
exception
when zero_divide then
dbms_output.put_line('除数不能为0');
when value_error then
dbms_output.put_line('赋值错误');
end;
--太多记录数的异常
declare
emp_row emp%rowtype; --记录类型变量接收多条记录
begin
select * into emp_row from emp;
exception
when too_many_rows then
dbms_output.put_line('太多记录数了');
when others then --不清楚类型 可以采用最大范围的 others放到最后 相当于Java的exception
dbms_output.put_line('出现异常');
end;
/*
自定义异常 自己声明变量 类型为exception
emp_exception exception 声明异常
抛出异常 raise
*/
--需求:查询部门下的员工信息,如果没有员工 抛出异常
declare
cursor dept_emp is select * from emp where deptno=40;
emp_row emp%rowtype;
noemp_dept exception; --声明没有员工的自定义异常
begin
open dept_emp;
fetch dept_emp into emp_row;
if dept_emp%notfound then
--没有提取到员工抛出自定义异常
raise noemp_dept;
end if;
close dept_emp;
exception
when noemp_dept then
dbms_output.put_line('部门没有员工,快点招人吧');
end;
/*
存储过程 封装的一段代码块 编译好放在服务器 调用直接运行
提升开发效率
提升运行效率
创建语法: create [or replace] procedure 过程名(参数名 in|out 参数数据类型)
as|is
--声明变量
begin
--代码块
end;
过程的调用
在begin 和end之间 过程名传参数直接调用
*/
--创建存储过程 实现增加某个员工的工资100
--增加工资前后 输出原始的工资和增加后的工资
create or replace procedure add_sal(eno in number)
as
emp_sal emp.sal%type;
begin
--1.先查询原始工资 输出
select sal into emp_sal from emp where empno=eno;
dbms_output.put_line('原始工资为==='||emp_sal);
--2.给传入的编号员工增加100工资
update emp set sal =sal+100 where empno=eno;
commit;
--3.查询之后的工资输出
select sal into emp_sal from emp where empno=eno;
dbms_output.put_line('增加后工资为==='||emp_sal);
end;
--调用过程增加7654的工资
declare
begin
add_sal(7654);
end;
--------需求:定义存储过程统计某个员工的年薪-----------
create or replace procedure count_sal(eno in number,year_sal out number)
as
begin
select sal*12+nvl(comm,0) into year_sal from emp where empno = eno;
end;
--调用过程得到 7369的年薪
declare
emp_sal number ;
begin
count_sal(7369,emp_sal);
dbms_output.put_line('年薪为===='||emp_sal);
end;
--通过存储过程得到某个部门的员工数据
/*
cursor
sys_refcursor 装入数据使用 open for装入数据
*/
create or replace procedure dept_emp_pro(dno in number,dept_emp out sys_refcursor)
as
begin
open dept_emp for select * from emp where deptno=dno;--使用传递的部门编号装入数据
end;
--调用过程得到10号部门的员工数据
declare
dept_emp sys_refcursor;
emp_row emp%rowtype;
begin
dept_emp_pro(10,dept_emp);
--循环游标提取数据
loop
fetch dept_emp into emp_row;
exit when dept_emp%notfound;
dbms_output.put_line('编号=='||emp_row.empno||'==姓名=='||emp_row.ename);
end loop;
close dept_emp;
end;
/*
存储函数 封装的一段代码块 编译好放在服务器 调用直接运行
提升开发效率
提升运行效率
创建语法: create [or replace] function 函数名(参数名 in|out 参数数据类型) retun 数据类型
as|is
--声明变量
begin
--代码块
return 变量;
end;
函数的调用
在begin 和end之间 函数名传参数直接调用 必须有变量接收返回值
*/
--使用函数得到 某个员工的年薪
create or replace function count_fun_sal(eno in number,emp_sal out number) return number
as
sal number :=0;
begin
select sal*12+nvl(comm,0) into emp_sal from emp where empno=eno;--赋值年薪给输出参数
return sal;
end;
--调用函数得到年薪
declare
emp_year_sal number;
emp_sal number;
begin
emp_sal := count_fun_sal(7369,emp_year_sal);
dbms_output.put_line(emp_year_sal);--年薪
dbms_output.put_line(emp_sal); --0
end;
--不用输出参数得到年薪
create or replace function count_fun_noout(eno in number) return number
as
sal number :=0;
begin
select sal*12+nvl(comm,0) into sal from emp where empno=eno;--赋值年薪给变量
return sal;
end;
--调用无out函数得到年薪
declare
emp_sal number;
begin
emp_sal := count_fun_noout(7369);
dbms_output.put_line(emp_sal); --年薪
end;
/*
过程和函数的总结
1.过程和函数的创建 关键字不一致
2.函数的创建 必须声明返回的数据类型
3.函数的代码块 必须返回变量
4.函数的调用必须接收返回值
5.函数可以用在select 语句中
使用场景:
通用规范:java代码调用过程处理逻辑
在处理逻辑的过程中需要用到功能性的封装
可以调用函数
过程和函数都可以互换,也可以互相调用
*/
select nvl(comm,0) from emp;
--通过自己定义的函数得到年薪
select emp.* ,count_fun_noout(empno) from emp;
/*
触发器 看作一个监视 监视对表中数据的操作
如果操作满足了触发器的执行条件 触发器自动执行
create [or replace] trigger 触发器名称
after|before --执行时机
insert|update|delete --监视动作
on 表名 --监视的表名
for each row --行级触发器 :new 将要操作之后的记录
:old 操作之前的记录
declare
begin
end;
*/
--使用触发器监视数据插入 如果插入员工输出欢迎语句
create or replace trigger insert_tri
after
insert
on p
declare
begin
dbms_output.put_line('欢迎加入大家庭!');
end;
---插入数据测试效果
insert into p values(1,'zs');
commit;
---触发器限制员工数据的插入 休息日不允许插入数据
/*
raise_application_error(v1,v2);v1是错误的代码 -20000 -20999
v2是错误的提示语 自定义
*/
create or replace trigger insert_no_workday
before
insert
on p
declare
v_day varchar2(10) ;
begin
--1.得到当前的星期
select to_char(sysdate,'day') into v_day from dual;
--2.判断当前的星期是否是休息日()
if trim(v_day) in ('friday','sunday') then
--3.如果是休息日 阻止插入 使用错误弹框提示
raise_application_error(-20001,'今天休息,不接待');
end if;
end;
select to_char(sysdate,'day') from dual;
--需求:监视数据修改,不能降低工资的操作
create or replace trigger can_not_low
before
update
on emp
for each row
declare
begin
--如何判断为降低工资的操作
if :new.sal < :old.sal then
--不允许修改
raise_application_error(-20002,'工资不能降低');
end if;
end;
--修改emp 7369的工资 降低100
update emp set sal = sal-100 where empno=7369;
/*
触发的真实应用
触发器实现 id 自增长
*/
create or replace trigger auto_inr_tri
before
insert
on p
for each row
declare
begin
--补全的id必须是一个自增长的数值
--触发器补全id
select order_sequence.nextval into :new.pid from dual;
end;
insert into p(pname) values('zs');
commit;
基本查询
select 列名|* from 表
oracle语法要求严谨 必须有from 表才可以
*/
select emp.* from emp;
select emp.*,1+1 from emp;
select 1+1 from emp
--显示一条记录 去除重复 distinct
select 1+1 from emp where empno = 7369
/*
dual表 虚拟表 没有实际意义 为了补全oracle的语法
*/
select 1+1 from dual
-------------------------------------------
--需求:查询员工编号 员工姓名 员工工作
select empno,ename,job,sal from emp;
--起别名 --
---数字 特殊字符(#$_) 空格必须使用双引号
select empno as "编号",ename "员工姓名",job 工作 from emp;
select empno as "编号",ename "员工姓名",job 工 作 from emp;--空格引起语法错误
select empno as "编!号",ename "员工姓名",job "工 作" from emp;--特殊字符引起语法错误
select empno as "编!号",ename 1234,job "工 作" from emp;--数字引起错误
select empno as 编#号,ename "1234",job "工 作" from emp;
--查询员工的工作-- 关键字 distinct
select distinct job from emp;
--查询员工的年薪
select * from emp;
select sal*12+comm from emp;
--null值参与运算结果为null if comm==null 计算加0
--nvl(v1,v2)v1原始数值 如果v1为null返回v2 v1不为空 返回v1
select sal*12+nvl(comm,0) from emp;
select sal*12+nvl(comm,0) 年薪 from emp;
--列值的拼接 员工编号: 7499 员工姓名: SMITH
--oracle使用concat函数实现列值拼接 --只支持两个参数的拼接
select concat('员工编号:',empno) from emp;
--嵌套实现 多重嵌套很麻烦
select concat(concat('员工编号:',empno),' 员工姓名') from emp;
--java实现方式 员工编号:'+empno+' 员工姓名'
--oracle特有的连接符 ||
select '员工编号:'||empno||' 员工姓名'||ename 个人简介 from emp;
---------------------------------------
/*
select *|列 from 表 where 条件
条件表达式
比较运算 > < = >= <= != <>
逻辑运算 and or not
其余运算
like 模糊查询 % 匹配0个或者多个
_ 占位一个字符
between and 判断区间 包含边界
in not in 判断范围
is null is not null 判断空值
*/
--查询工作不是 MANAGER 的员工信息
select * from emp where job !='MANAGER'
select * from emp where job <>'MANAGER'
--查询员工的工作 是 MANAGER 或者是PRESIDENT的员工信息
select * from emp where job = 'MANAGER' or job = 'PRESIDENT'
--使用逻辑非 not 实现不是MANAGER的员工信息
--JAVA 非的使用 !job.equals("MANAGER")
select * from emp where not job = 'MANAGER'
--查询员工姓名包含M的员工信息
select * from emp where ename like '%M%'
--查询员工姓名第二位为M的员工信息
select * from emp where ename like '_M%'
--查询员工的工资 在 1500----3000之间的员工信息
select * from emp where sal between 1500 and 3000
--查询员工的工作 是 MANAGER 或者是PRESIDENT的员工信息
select * from emp where job in ('MANAGER','PRESIDENT')
--查询有奖金的员工信息
select * from emp where comm is not null and comm !=0
select * from emp where comm > 0
--对数据有特殊的排序要求
/*
order by 列 desc|asc
升序asc 默认
*/
--按照工资做从低到高的排序
select * from emp order by sal
--按照工资做从高到低的排序
select * from emp order by sal desc
--按照奖金从高到低排序
select * from emp order by comm desc
--null的倒叙排序默认在上面 置于末尾使用 nulls last
select * from emp order by comm desc nulls last
/*
函数 数据库提供一些方法支持 数据的查询或者处理
单行函数
针对每一条记录的列值做处理 nvl concat
数值函数
字符函数
日期函数
转换函数
通用函数
多行函数 参数运算的记录为多条 返回结果为一条
聚合函数
五个聚合
count 统计记录数
sum 求和统计
avg 求平均值
max 求最大值
min 求最小值
*/
/*
数值函数 对数值处理的函数
四舍五入 round(v1,v2) v1原始数值 v2是保留的小数位数
数值截取 trunc(v1,v2) v1原始数值 v2是保留的小数位数
不做四舍五入操作 直接舍去数值
求余数 mod(v1,v2) java 10%3 ==1
*/
--43.726四舍五入
select round(43.726) from dual; --默认小数位数为 0 44
select round(43.726,0) from dual;--44
select round(43.726,1) from dual;--43.7
select round(43.726,2) from dual;--43.73
select round(43.726,-1) from dual;-- 40
select round(43.726,-2) from dual;--0
select round(53.726,-2) from dual;--100
--数值截取
select trunc(43.726) from dual; --43
select trunc(43.726,0) from dual;--43
select trunc(43.726,1) from dual;--43.7
select trunc(43.726,2) from dual;--43.72
select trunc(43.726,-1) from dual;-- 40
select trunc(43.726,-2) from dual;--0
select trunc(53.726,-2) from dual;--0
--求余数
select mod(10,3) from dual; ---1
/*
字符函数
获取字符串长度 length()
截取字符 substr(v1,v2,v3) v1原始字符串 v2起始位置 v3截取长度
大小写转换 upper lower
替换字符 replace(v1,v2,v3) v1原始字符串 v2被替换的字符串 v3替换成的字符
替换匹配的所有字符
去除空格 trim() 去除两端的空格
*/
--abcde
select length('abcde') from dual; --5
--截取字符
--从0和1开始都是第一位
select substr('abcde',0,2) from dual;-- ab
select substr('abcde',1,2) from dual;-- ab
select substr('abcde',-1,2) from dual;-- e
select substr('abcde',-2,2) from dual;-- de
--大小写转换
/*
使用场景 忽略数据库中的大小写
xzY3 XZY3 xzy3 xzY3
查询SMITH 的员工信息 smith SMITH smiTH
*/
select * from emp where ename = upper('smith');
select * from emp where ename = upper('SMITH');
select * from emp where ename = upper('smiTH');
--替换字符串
--hello
select replace('hello','l','o') from dual; --heooo
--去除空格 __abc_de_
select trim(' abc de ') from dual;--abc de
select replace(' abc de ',' ','') from dual;
/*
日期函数
获取当前时间 sysdate
给系统时间增加月数 add_months(dataV1,monthV2)
获取两个时间间隔的月数 months_between(dat21,date2)
*/
select sysdate from dual;
--给当前时间增加两个月
/*
ticket 表
id orderNum createTime invalidTime
1 1122333 2018-1-12 2018-4-12
2 1122444 2018-1-12 2018-6-12
select * from ticket where sysdate<invalidTime and invalidTime<add_months(sysdate,1)
*/
select add_months(sysdate,2) from dual;
--查询员工入职到现在多少个月
select months_between(sysdate,hiredate) from emp;
--查询员工入职到现在多少天 日期和日期做计算结果为天数
select round(sysdate-hiredate) from emp;
/*
转换函数
数值互换字符串
日期互换字符串
to_number 转成数值
to_char 转成字符串
to_date 转成日期
*/
select to_number('123') +1 from dual;
select '123' +1 from dual; --数字格式的字符串自动转换
--日期和字符串的转换
select to_char(sysdate,'yyyy-mm-dd') from dual;
select to_char(sysdate,'yyyy') from dual;
select to_char(sysdate,'mm') from dual;
select to_char(sysdate,'dd') from dual;
select to_char(sysdate,'day') from dual; --星期的格式
select to_char(sysdate,'yyyy-mm-dd hh:mi:ss') from dual;--oracle数据库分钟是mi
--字符串转换日期
select to_date('2018-03-19','yyyy-mm-dd') from dual;
select to_date('2018-03-19','yyyy-mm-dd hh:mi:ss') from dual;
--jsp页面取值数据库是年月日 页面显示时分秒会自动显示00:00:00
select to_date('2018-03-19 17:13:33','yyyy-mm-dd hh24:mi:ss') from dual;
--jsp页面的24小时和12小时切换 HH hh
/*
通用函数
nvl()处理空值 ifnull()
ios android
nvl2(v1,v2,v3)v1是原始数值 v2是v1不为空的返回值 v3是v1为空的返回值
处理空值
concat()拼接值
*/
select nvl2(1,2,3) from dual;---2
select nvl2(null,2,3) from dual;---3
/*
聚合函数
特点:忽略null值 列值为空不参与运算
count 统计记录数
sum 求和统计
avg 求平均值
max 求最大值
min 求最小值
**/
--需求统计员工的个数
/*
三种统计 如果表中没有唯一索引 推荐使用后两种
如果存在索引 三种效率一致
*/
select count(*) from emp;
select count(empno) from emp;
select count('abc') from emp;
--使用奖金的列做数量统计
select count(comm) from emp; --4
--查询员工的奖金总和
select sum(comm) from emp; --2200
--查询员工的平均奖金
select avg(comm) from emp; --550
/*
分组统计
group by 列
分组之后的数据 使用having 聚合函数
分组之前的数据 使用where
规则限制 如果group by作为分组,那么select 语句中只能查询 group by后面的列
和其余的聚合函数
*/
--需求:统计每个部门的平均工资
select * from emp
select deptno,avg(sal) from emp group by deptno
--查询部门平均工资>2000的部门编号
select deptno,avg(sal) from emp group by deptno having avg(sal)>2000
--查询部门平均工资 参与部门平均工资运算的员工工资必须大于1500
select deptno,avg(sal) from emp where sal>1500 group by deptno
--统计同一个工作,同一个部门的员工数量
--多列分组 使用多个列值 做分组统计 列值完全一致才会分为一组
select deptno,job, count(*) from emp group by deptno,job
--加入员工的姓名查询
select ename, deptno,job, count(*) from emp group by deptno,job,ename
/*
多表查询 从多张表查询数据 分析数据来源为多张表
*/
--查询员工信息和员工的部门信息 dept
select * from emp;
select * from dept;
--同时查询员工表和部门表 --加入关联条件提取有效数据
select * from emp,dept where emp.deptno=dept.deptno
/*
内连接 隐式内连接 select * from A,B where A.列=B.列
显示内连接 select * from A inner join B on A.列=B.列
查询特点 作为关联查询的表 必须有完全匹配的条件数据 才会提取记录
*/
--使用显式内连接实现
select * from emp inner join dept on emp.deptno=dept.deptno
/*
外连接 左外连接 select * from A left join B on A.列=B.列
特点:以左表为基准,左表数据要全部显示,右表数据
作为补充显示 没有匹配的数据 显示为null
右外连接 select * from B right join A on A.列=B.列
特点:以右表为基准,右表数据要全部显示,左表数据
作为补充显示 没有匹配的数据 显示为null
*/
--需求:查询部门信息 和部门的员工信息 没有员工的部门信息也要显示
--左外连接
select * from dept left join emp on dept.deptno = emp.deptno
--右外连接
select * from emp right join dept on dept.deptno = emp.deptno
--强制要求dept列值显示在左
select dept.*,emp.* from emp right join dept on dept.deptno = emp.deptno
/*
oracle特有外连接 (+)
根据需求将符号(+)放在作为补充显示的表的列后面
select * from A,B where A.列(+)=B.列
*/
select * from emp inner join dept on emp.deptno(+)=dept.deptno
/*
自连接 自己跟自己做关联查询 为了区分两个表 必须起别名
select * from A A1,A A2 where A1.列=A2.列
使用场景: 查询的数据来源为同一张表
*/
--查询员工的信息 和员工的领导信息
select * from emp e,emp m where e.mgr = m.empno
--需求:查询员工编号 员工姓名,员工的 领导编号,领导姓名,员工的部门名称
--1.定义查询数据 员工信息 领导信息 部门信息
--2.定义数据来源 emp emp dept
--3.分析关联表和关联条件
select e.empno,e.ename,m.empno mgr_no,m.ename mgr_name ,d.dname
from emp e,emp m ,dept d
where e.mgr = m.empno and e.deptno = d.deptno
--再上面基础之上,再查询员工的工资等级 salgrade
select * from salgrade
select e.empno,e.ename,s1.grade,d.dname,
m.empno mgr_no,m.ename mgr_name
from emp e,emp m ,dept d,salgrade s1
where e.mgr = m.empno and e.deptno = d.deptno
and e.sal between s1.losal and s1.hisal
--再上面基础之上 再查询领导的工资等级
select e.empno,
e.ename,
s1.grade,
d.dname,
m.empno mgr_no,
m.ename mgr_name,
s2.grade
from emp e, emp m, dept d, salgrade s1, salgrade s2
where e.mgr = m.empno
and e.deptno = d.deptno
and e.sal between s1.losal and s1.hisal
and m.sal between s2.losal and s2.hisal
/*
订单查询 火车票
订单号 订单的时间 订单的总价钱 ---订单表
列车班次 发车时间 --列车表
购票的用户信息 --用户表
乘客信息 --乘客表
支付的信息 --支付表
联系人信息 --联系人表
*/
/*
子查询:在查询语句中可以嵌套查询语句不限制一条
语法: 单行子查询 select * from A where A.列 = (sql语句返回唯一的一个值)
多行子查询 select * from A where A.列 in (sql语句返回单列多值)
select * from A,(sql语句得到临时表) T where A.列=T.列
*/
--范例:查询比员工7654工资高,同时从事和7788相同工作的员工信息?
--1.员工信息
--2.emp表
--3.查询条件 sal>7654的工资 and job=7788的工作
--先查询7654的工资 和7788的工作
select sal from emp where empno=7654 --1250
select job from emp where empno=7788 --ANALYST
select * from emp where sal >1250 and job = 'ANALYST'
--使用sql语句替换查询条件
select * from emp where
sal >(select sal from emp where empno=7654)
and job = (select job from emp where empno=7788)
--范例:查询每个部门的最低工资,和最低工资的员工信息及员工的部门名称
--1.部门最低工资 员工信息 部门名称
--得到部门最低工资的数据来源
select deptno,min(sal) d_min from emp group by deptno
--2.sql临时表,emp,dept
--3.关联条件
select e.empno,e.ename,e.sal,e.deptno,d_m.d_min,d.dname from emp e,
(select deptno,min(sal) d_min from emp group by deptno) d_m,
dept d
where e.deptno = d_m.deptno and e.sal = d_m.d_min
and e.deptno = d.deptno
--查询不是领导的员工信息
--1.员工信息
--2.emp
--3.条件 不是领导
/*
数据查询 先判断条件成立 提取数据
null值的判断只能是 is 判断 其余表达式 UNKONW
*/
select * from emp
where empno not in( select mgr from emp where mgr is not null)
select min(sal) d_min from emp group by deptno
--子查询错误示例
select * from emp
where sal = (select min(sal) d_min from emp group by deptno)
---只要员工的工资是 800 950 1300 都会提取
select * from emp
where sal in (select min(sal) d_min from emp group by deptno)
/*
exists 存在
判断sql语句是否存在 exists(sql) 如果sql结果集存在 表达式true
结果集不存在 表达式false
子查询执行顺序 先走括号内子查询语句 得到结果用于主查询判断
exists如果作为子查询 子查询语句关联主查询的表列值,那么执行顺序发生更改
先走主查询,得到主查询的一条记录,判断子查询是否成立,如果成立,返回当前的
主查询记录
使用场景:如果主查询的记录结果集比子查询的表中多 推荐使用 in
如果子查询的记录结果集比主查询的多 推荐使用 exists
先走的查询语句 记录少,效率高
*/
--exists的简单示例
select * from emp where exists(select * from dept)--emp的所有记录
select * from emp where exists(select * from dept where deptno=1234) --没有结果
--查询有员工的部门信息
--使用之前学过的方式 实现
--1.部门信息
--2.部门表 dept
--3.条件 部门有员工
select * from dept where deptno in ( select deptno from emp)
--使用exists实现
select * from dept where
exists(select * from emp where emp.deptno=dept.deptno)
/*
分页效果实现 mySql 使用limit 0 3
需求:提取5--10条记录
oracle使用 rownum 是一个伪列,查询数据时候才会产生一系列数值 1 2 3 4
作用是实现分页的 必须借助于rownum 必须使用子查询
*/
--rowNum的示例
select rownum,emp.* from emp;
--提取前三条
select rownum,emp.* from emp where rownum < 4
--提取五条以后的数据
select rownum,emp.* from emp where rownum > 5
--先查询生成rownum 再用于条件过滤判断
select * from (select rownum r,emp.* from emp) t where t.r>5 and t.r<11
--分页优化结果
select * from (select rownum r,emp.* from emp where rownum < 11) t where t.r>5
--找到员工表中工资最高的前三名
--1.先按照工资倒序排序
select * from emp order by sal desc
--2.加入rownum 先生成rownum 按照工资排序 顺序错乱
select rownum,emp.* from emp order by sal desc
--3.先排好顺序,再查询生成rownum
select rownum,t.* from (select * from emp order by sal desc)t
--4.提取前三条数据
select rownum,t.*
from (select * from emp order by sal desc)t where rownum<4
/*
rowid 指的是数据库在保存记录的时候,生成的真实物理地址 唯一不变
用于数据库操作记录使用
rownum 查询才会生成,而且根据条件筛选 排序规则发生变化 用于分页使用
*/
select * from emp;
select rowid,emp.* from emp;
--找到员工表中薪水大于本部门平均薪水的员工信息。
--1.部门平均工资 员工的信息
select deptno,avg(sal) d_avg from emp group by deptno
--2. 临时表 emp
--3.工资大于本部门平均工资的员工
select * from emp ,
(select deptno,avg(sal) d_avg from emp group by deptno) d_a
where emp.deptno = d_a.deptno and emp.sal >d_a.d_avg
/*
条件表达式的使用
sql语句数据库通用的表达式
case 列
when 列值1 then 处理语句
when 列值2 then 处理语句
when 列值3 then 处理语句
else
默认处理
end
--oracle数据库条件表达式 decode(列,列值1,显示值1,列值1,显示值1,默认值)
*/
---使用条件表达式实现 员工等级的显示 如果1 显示一级
select e.empno,e.ename,
case s1.grade
when 1 then '一级'
when 2 then '二级'
when 3 then '三级'
else
'四级'
end
,
d.dname,
m.empno mgr_no,m.ename mgr_name
from emp e,emp m ,dept d,salgrade s1
where e.mgr = m.empno and e.deptno = d.deptno
and e.sal between s1.losal and s1.hisal
---使用docode函数实现
select e.empno,e.ename,
decode(s1.grade,1,'一级',2,'二级',3,'三级','四级') 等级
,
d.dname,
m.empno mgr_no,m.ename mgr_name
from emp e,emp m ,dept d,salgrade s1
where e.mgr = m.empno and e.deptno = d.deptno
and e.sal between s1.losal and s1.hisal
--统计每年入职的员工个数
select * from emp;
select to_char(emp.hiredate,'yyyy') hire_year,count(1) hire_count
from emp group by to_char(emp.hiredate,'yyyy')
--1.使用条件表达式 处理结果尝试竖起来一列
select decode(t.hire_year,'1987',t.hire_count) "1987" from
(select to_char(emp.hiredate,'yyyy') hire_year,count(1) hire_count
from emp group by to_char(emp.hiredate,'yyyy')) t
--2.使用聚合函数忽略null值的记录
select sum(decode(t.hire_year,'1987',t.hire_count)) "1987" from
(select to_char(emp.hiredate,'yyyy') hire_year,count(1) hire_count
from emp group by to_char(emp.hiredate,'yyyy')) t
--3.使用聚合函数补全其余的列
select sum(decode(t.hire_year,'1980',t.hire_count)) "1980",
sum(decode(t.hire_year,'1981',t.hire_count)) "1981",
sum(decode(t.hire_year,'1982',t.hire_count)) "1982",
sum(decode(t.hire_year,'1987',t.hire_count)) "1987"
from
(select to_char(emp.hiredate,'yyyy') hire_year,count(1) hire_count
from emp group by to_char(emp.hiredate,'yyyy')) t
--4.使用sum求和运算补全total
select sum(t.hire_count) total,
avg(decode(t.hire_year,'1980',t.hire_count)) "1980",
max(decode(t.hire_year,'1981',t.hire_count)) "1981",
min(decode(t.hire_year,'1982',t.hire_count)) "1982",
sum(decode(t.hire_year,'1987',t.hire_count)) "1987"
from
(select to_char(emp.hiredate,'yyyy') hire_year,count(1) hire_count
from emp group by to_char(emp.hiredate,'yyyy')) t
/*
集合的运算
交集 取两个集合共同的部分 intersect A(1,2,3) B(2,3,4) A交B (2,3)
并集 取两个集合最大的范围 union A(1,2,3) B(2,3,4) A并B (1,2,3,4)
包含重复数据的合并 union all A(1,2,3) B(2,3,4) A并B (1,2,3,2,3,4)
差集 从一个集合去掉另外一个集合剩余的部分 minus A(1,2,3) B(2,3,4) A差B (1)
使用场景:
跨表的数据合并
规则限制 列的数量一致 类型一致
*/
--范例:工资大于1500,或者是20部门下的员工
select * from emp where sal>1500 or deptno=20
--使用集合实现
select * from emp where sal>1500
union
select * from emp where deptno=20
--合并包含重复的
select * from emp where sal>1500
union all
select * from emp where deptno=20
--范例:工资大于1500,并且是20部门下的员工
select * from emp where sal>1500 and deptno=20
--使用集合
select * from emp where sal>1500
intersect
select * from emp where deptno=20
--范例:1981年入职的普通员工(不包括经理,总裁)
--使用之前的方式实现
select * from emp where to_char(hiredate,'yyyy')='1981' and
job not in ('PRESIDENT','MANAGER')
--使用集合实现
select * from emp where to_char(hiredate,'yyyy')='1981'
minus
select * from emp where job in ('PRESIDENT','MANAGER')
--合并员工的数据和领导的数据
select empno,ename from emp
union
select mid,mname from manager
--类型不匹配合并失败
select ename,empno from emp
union
select mid,mname from manager
---查询公司的所有员工 编号 姓名 工作
select empno,ename,job from emp
union
select mid,mname,'manager' from manager
--创建一个 manager表 作为公司的领导表
create table manager(
mid number(9),
mname varchar(11)
)
insert into manager values(1,'zs');
insert into manager values(2,'ls');
commit;
/*
DDL语句 数据定义语言 使用sql语句创建管理数据库的对象
表空间 实例分配的一块空间 用于项目开发 建表和插入数据
创建语法:
create tablespace 表空间名
datafile '物理文件路径'
size 初始化大小
autoextend on
next 扩展大小
*/
---创建表空间示例--管理员才能创建
create tablespace sinosoft
datafile 'c:\sinosoft.dbf'
size 100m
autoextend on
next 10m
---操作表空间 建表和插入数据 管理员创建用户
create user sinosoft
identified by sinosoft
default tablespace s inosoft
--对用户授权
/*
授权语法:
grant 权限 to 用户
权限分类: connect 最基本的权限
resource 比较高级权限
dba 最高级权限 相当于管理员
*/
--管理员授予用户 connect 权限
grant connect to itheima_310
--管理员授予itheima dba最高级权限
grant dba to itheima_310
--建表测试
/*
create table 表名(
列名 列的数据类型
)
*/
/*
oracle数据库表 根据表空间划分
同一个表空间 表根据用户划分
*/
create table p(
pid number(9),
pname varchar(10)
)
/*
设计表的步骤
1.表中设计的列 练习自己定义
2.列的数据类型
数值类型 int long short bigint tinyint double float
oracle number(v1,v2) 数值类型 v1是数值总长度
v2是数值的小数位数
v1默认不写 32位长度
v2默认不写 0 取整数
number(6,2) ---9999.99
字符类型
char 固定长度的字符类型 char(10) 存储 'zs'
实际2个长度 占用空间10个长度
varchar
可变长度的字符类型 varchar(10) 存储 'zs'
实际2个长度 占用空间2个长度
varchar2
可变长度的字符类型 varchar(10) 存储 'zs'
实际2个长度 占用空间2个长度
日期类型
mySql的日期格式
date格式 存储的日期为 yyyy-mm-dd
datetime格式 存储的日期为 yyyy-mm-dd hh:mi:ss
timestamp 默认存储秒后3位毫秒
oracle日期格式
date格式 存储的日期为 yyyy-mm-dd hh:mi:ss
timestamp 更精确的日期类型 精确到秒后9位 纳秒
大文本类型
clob 字符类型大文本 4G的长度
blob 二进制类型大文本 4G的长度
long 长文本 2G的长度
3.约束
主键约束 primary key
外键约束 foreign key
非空约束 not null
唯一约束 unique
检查约束 check(gender in (1,0))--判断列值是否满足表达式
--自定义约束名
constraint 约束名 约束类型(列名)
*/
--创建person表 id 姓名 电话 性别
create table person(
pid number(9),
pname varchar2(11) not null,
phone varchar2(11) unique,
gender number(1) check(gender in (0,1)),
constraint pk_person_pid primary key(pid)
)
--插入数据测试约束
--oracle的事务需要手动选择提交或者回滚
insert into person values(1,'zs','11122223333',1);
insert into person values(1,'zs','11122223333',1);--违反主键约束
insert into person values(2,'zs','11122223333',1);--违反唯一约束
insert into person values(2,'zs','11122224444',1);
insert into person values(2,null,'11122224444',1);--违反非空约束
insert into person values(2,'','11122224444',1); --空串当作null处理
insert into person values(3,'xiaofang','11122225555',9); --违反检查约束
insert into person values(3,'xiaofang','11122225555',0);
commit;
/*
修改表结构
alter table 表名
增加一列 add(列名 数据类型)
修改列数据类型 modify(列名 数据类型)
重命名列 rename column 旧列名 to 新列名
删除一列 drop column 列名
增加约束 add constraint 约束名 约束类型(列名)
*/
--新增用户的地址列 address
alter table person add(address varchar2(100))
--修改列的数据类型 address 改成 char 类型 40个长度
alter table person modify(address char(40))
alter table person modify(pname number(10))--更改类型保证为空
--更改性别的gender 改成sex
alter table person rename column gender to sex
--删除address列
alter table person drop column address
--增加p表的主键约束
alter table p add constraint pk_p_pid primary key(pid)
/*
DML语句 数据操纵语言 对表中数据做操作
插入数据 insert into 表名 values(.....)
insert into person(pid,pname,phone) values(2,'zs','11122224444');
---指定列名插入特定的列值
修改数据
update 表名 set 列名 = 值 where 条件
删除数据
delete from 表名 where 条件
delete from 表名 一条条删除 效率略低
truncate table 表名 摧毁表结构 重建表结构 效率高
*/
--需求:使用scott用户下的emp表做练习
select * from scott.emp;
--自己创建emp表 数据同scott表的数据完全一致
create table emp as select * from scott.emp;
--修改SMITH的工资 涨100块钱
update emp set sal =sal+100 where ename='SMITH';
commit;
/*
在存在主外键的情况下 删除主表的记录
开发规范:数据库表数据不允许物理删除 逻辑删除
1.先删除子表记录,再删除主表记录
2.设置外键为null
3.级联删除 删除主表记录的同时 ,把子表记录删除
java类的关联属性上 CASCADE.ALL
数据库在关联的列上做设置 级联删除 外键使用 on delete cascade 实现
4.强制删除主表
*/
--创建主表和从表
create table orders(
oid number(9) primary key ,
oname varchar2(15) ,
oprice number(6,2)
)
create table order_detail(
detail_id number(9) primary key,
detail_name varchar2(15),
detail_price number(6,2),
oid number(9),
constraint fk_detail_oid foreign key(oid) references orders(oid)
-- on delete cascade
)
---插入主表和从表的记录
insert into orders values(1,'订单1',1000.00);
insert into order_detail values(1,'订单1',1000.00,1);
commit;
------查看两张表的数据
select * from orders;
select * from order_detail;
insert into order_detail values(2,'订单1',1000.00,2);--违反外键约束
commit;
--删除主表记录测试
delete from order_detail where detail_id =1;
commit;
delete from orders where oid = 1;
commit;
--直接删除主表 cascade constraint --不推荐使用
drop table orders cascade constraint --删除了关联的约束
/*
事务 作为一个逻辑操作单元 执行的任务全部成功,全部失败
ACID 原子性 一致性 隔离性 持久性
没有隔离级别 脏读 幻读 不可重复读
事务的隔离级别
oracle 只有三种 READ COMMITED 默认级别
SERIALIZABLE 串行化
READ ONLY 只读
事务的保存点:
为了保证执行成功的任务 正常提交
声明事务保存点 savepoint 保存点名;
出现异常 回滚到保存点 rollback to 保存点
继续提交 commit;
*/
---保存点的示例
declare
begin
insert into orders values(1,'订单1',1000.00);
insert into orders values(2,'订单1',1000.00);
insert into orders values(3,'订单1',1000.00);
insert into orders values(4,'订单1',1000.00);
insert into orders values(5,'订单1',1000.00);
savepoint s1;--声明保存点 保存之前的任务
insert into orders values(6,'订单1',1000.00);
insert into order_detail values(1,'订单1',1000.00,100);--执行失败
commit;
exception
when others then
rollback to s1; --发生异常任务回滚
commit;
end;
/*
数据库的其余对象
视图
是一个虚拟表 不存储数据 只支持数据查询,数据来源为原始表
意义:为了数据的安全
为了权限的细分
作用:简化查询的sql语句
提高查询效率
数据不会经常变化 放到缓存可以
create view 视图名 as select 列 from 表
序列
索引
同义词
*/
--查询员工的信息 创建视图支持部分数据查询
create view emp_view as select empno,ename,job,deptno from emp;
--查询视图的数据
select * from emp_view;
--修改视图的数据
update emp_view set ename='SSSS' where ename='SMITH';
commit;
--创建只读的视图 支持查询
create view e_view as select empno,ename,job,deptno from emp with read only
update e_view set ename='SMITH' where ename='SSSS';
commit;
/*
序列 数据库生成的一系列数值 1 2 3 4
用于实现 主键 自增 mySql设置主键自增 auto_increment
oracle的自增长 必须借助于序列实现
创建序列
create sequence 序列名
属性:
currval ---当前值 序列目前生成的值
nextval ---下一个值 序列下一个生成的值
同样一条sql语句 不管nextval调用多少次 都是一个值
*/
--创建序列
create sequence order_sequence
--查询序列的两个属性
select order_sequence.currval from dual;--必须nextval调用才支持查询
select order_sequence.nextval from dual;--默认值从1开始生成 默认按照1自增
--插入数据使用序列实现自增长
insert into orders values(order_sequence.nextval,'订单1',1000.00);
commit;
/*
索引 看作一本书的目录 没有目录找固定的章节
挨页查看 效率低
用于提升数据检索速度 数据量大使用
创建索引
create index 索引名 on 表名(列)
复合索引
create index 索引名 on 表名(列1,列2)
使用通用规范 如果能使用多列索引 建议使用
多列索引会高于单列索引
*/
--测试索引的效果
--1.创建大数据量的表 5000000条记录
declare
begin
for i in 1..5000000 loop
insert into orders values(order_sequence.nextval,'订单'||order_sequence.nextval,1000.00);
end loop;
commit;
end;
--2.先查询没有索引 记录耗时
select * from orders where oname = '订单2222222' ---3.265
--3.创建索引
create index order_index on orders(oname)
--4.查询同样的条件 记录耗时
select * from orders where oname = '订单3333333'--0.063
--创建多列索引
create index order_fu_index on orders(oname,oprice)
--查询订单姓名和定价价钱
select * from orders where oname = '订单3333333' and oprice=1000.00 --0.063
select * from orders where oid=3333333
select 3.265/0.063 from dual;
/*
同义词 给用户的对象起别名
create synonym 同义词名 for 用户.对象
*/
create synonym dept_syn for scott.dept
select * from dept_syn
/*
数据的导入和导出
导出目的 备份数据
导入目的 还原数据
数据库整体迁移--专业数据库管理员
实现方式
命令行导入导出 必须安装数据库服务端
导出命令
exp 整个数据库导出 exp 用户名/密码 file='导出文件.dmp' full=y
按照用户导出 exp 用户名/密码 owner=用户名 file='导出文件.dmp'
按照表名导出 exp 用户名/密码 file='导出文件.dmp' tables=表名,表名2
imp 导入 更换exp为imp
图形化工具导入导出
tools --export user object --只能导出表结构 不能备份表数据
可以导出所有用户对象
--export tables
oracle导出 --必须安装数据库服务端
sql文件导出 --导出的文件为sql文件 导出的时候勾选create table
plsql导出 --导出的文件文件pde格式 导入数据勾选 create table
*/
/*
PLSQL 编程语句 procedure language 过程语言 在sql语句中加入处理过程的
语句 常见的条件判断 循环结构
基本结构
declare
--声明部分
--定义变量的位置
begin
--实现业务逻辑的代码块
end;
*/
---plSql简单示例
declare
v_n number(8) :=1; --定义数值类型的变量
v_s varchar2(10) :='s'; --定义字符类型的变量
begin
dbms_output.put_line('v_n===='||v_n);--输出语句相当于system.out.println();
dbms_output.put_line('v_s===='||v_s);
end;
--查询员工7654的工资 判断工资的数值 输出语句
/*
条件表达式 if的语法
if .. then ..
elsif .. then..
else
..
end if; --表达式结束
*/
declare
emp_sal number;
e_sal emp.sal%type; --引用类型变量
emp_row emp%rowtype; --记录类型变量
begin
select sal into e_sal from emp where empno=7654;--查询赋值使用into
dbms_output.put_line('e_sal===='||e_sal);
select * into emp_row from emp where empno=7654;
if emp_row.sal > 3000 then
dbms_output.put_line('工资大于3000==='||emp_row.sal);
elsif emp_row.sal < 1000 then
dbms_output.put_line('工资小于1000==='||emp_row.sal);
else
dbms_output.put_line('工资位于1000----3000==='||emp_row.sal);
end if;
end;
---------------------------------------------
/*
循环结构 java循环结构
for(){} while(){} do{}while()
-------------
loop
exit when 条件
end loop
----------------
while 条件 loop
end loop;
------------------
for 变量 in 范围 loop
end loop;
*/
---使用循环语句输出1----10的数字
declare
v_n number :=1;
begin
loop
exit when v_n>10;
dbms_output.put_line(v_n);
v_n := v_n+1;
end loop;
end;
----------
declare
v_n number :=1;
begin
while v_n<11 loop
dbms_output.put_line(v_n);
v_n := v_n+1;
end loop;
end;
----for循环---for(Customer c:list){}
declare
begin
for v_n in 1..10 loop
dbms_output.put_line(v_n);
end loop;
end;
/*
游标 光标
用于接收查询得到的记录结果集 ResultSet 需要提取 rs.next()
声明游标 cursor 游标名 is select * from 表名
打开游标 open 游标名
提取游标 fetch 游标名 into 记录类型变量
关闭游标 close 游标名
游标的属性:
%notfound 没找到
%found 找到
*/
declare
cursor emp_cursor is select * from emp; --查询所有员工赋值给游标
emp_row emp%rowtype;--声明记录类型变量 用于接收游标的提取
begin
open emp_cursor; --打开游标
if emp_cursor%found then
dbms_output.put_line('found');
elsif emp_cursor%notfound then
dbms_output.put_line('notfound');
elsif emp_cursor%found is null then
dbms_output.put_line('null');
end if;
--游标的属性 先提取 再判断使用
fetch emp_cursor into emp_row;
while emp_cursor%found loop --没满足条件
dbms_output.put_line('empno=='||emp_row.empno||'==ename=='||emp_row.ename);
fetch emp_cursor into emp_row;
end loop;
close emp_cursor;
end;
--loop循环提取游标
declare
cursor emp_cursor is select * from emp; --查询所有员工赋值给游标
emp_row emp%rowtype;--声明记录类型变量 用于接收游标的提取
begin
open emp_cursor; --打开游标
loop
fetch emp_cursor into emp_row;
exit when emp_cursor%notfound;
dbms_output.put_line('empno=='||emp_row.empno||'==ename=='||emp_row.ename);
end loop;
close emp_cursor;
end;
--需求:带参数游标提取某个部门的员工记录
declare
cursor emp_cursor(dno number) is select * from emp where deptno =dno; --查询所有员工赋值给游标
emp_row emp%rowtype;--声明记录类型变量 用于接收游标的提取
begin
open emp_cursor(10); --打开游标
loop
fetch emp_cursor into emp_row;
exit when emp_cursor%notfound;
dbms_output.put_line('empno=='||emp_row.empno||'==ename=='||emp_row.ename);
end loop;
close emp_cursor;
end;
/*
系统引用游标
emp_cursor sys_refcursor;--声明变量类型为系统引用游标 不需要给游标指定结果集
open emp_cursor for select * from 表
*/
--使用系统引用游标查询员工的记录结果集
declare
emp_cursor sys_refcursor;--声明变量类型为系统引用游标 不需要给游标指定结果集
emp_row emp%rowtype;--声明记录类型变量 用于接收游标的提取
begin
open emp_cursor for select * from emp;
loop
fetch emp_cursor into emp_row;
exit when emp_cursor%notfound;
dbms_output.put_line('empno=='||emp_row.empno||'==ename=='||emp_row.ename);
end loop;
close emp_cursor;
end;
/*
例外 异常
分类:运行时异常 编译时异常 系统定义好的异常类型
自定义异常 new 自定义类 继承 Exception
抛出自定义异常 赋值错误代码 提示语句
使用场景: 业务场景不符合规则
异常处理 try{}catch(IndexOutOfBoundException e){}catch(Exception e){}
exception --处理异常的代码块
when 异常类型 then 异常处理
when 异常类型 then 异常处理
*/
--除数为0的异常
declare
v_n number :=1;
v_m number :=0;
begin
v_n:=v_n/v_m;
exception
when zero_divide then
dbms_output.put_line('除数不能为0');
end;
--赋值错误异常
declare
v_n number :=1;
v_m number :=0;
begin
v_n:='ss';
v_n:=v_n/v_m;
exception
when zero_divide then
dbms_output.put_line('除数不能为0');
when value_error then
dbms_output.put_line('赋值错误');
end;
--太多记录数的异常
declare
emp_row emp%rowtype; --记录类型变量接收多条记录
begin
select * into emp_row from emp;
exception
when too_many_rows then
dbms_output.put_line('太多记录数了');
when others then --不清楚类型 可以采用最大范围的 others放到最后 相当于Java的exception
dbms_output.put_line('出现异常');
end;
/*
自定义异常 自己声明变量 类型为exception
emp_exception exception 声明异常
抛出异常 raise
*/
--需求:查询部门下的员工信息,如果没有员工 抛出异常
declare
cursor dept_emp is select * from emp where deptno=40;
emp_row emp%rowtype;
noemp_dept exception; --声明没有员工的自定义异常
begin
open dept_emp;
fetch dept_emp into emp_row;
if dept_emp%notfound then
--没有提取到员工抛出自定义异常
raise noemp_dept;
end if;
close dept_emp;
exception
when noemp_dept then
dbms_output.put_line('部门没有员工,快点招人吧');
end;
/*
存储过程 封装的一段代码块 编译好放在服务器 调用直接运行
提升开发效率
提升运行效率
创建语法: create [or replace] procedure 过程名(参数名 in|out 参数数据类型)
as|is
--声明变量
begin
--代码块
end;
过程的调用
在begin 和end之间 过程名传参数直接调用
*/
--创建存储过程 实现增加某个员工的工资100
--增加工资前后 输出原始的工资和增加后的工资
create or replace procedure add_sal(eno in number)
as
emp_sal emp.sal%type;
begin
--1.先查询原始工资 输出
select sal into emp_sal from emp where empno=eno;
dbms_output.put_line('原始工资为==='||emp_sal);
--2.给传入的编号员工增加100工资
update emp set sal =sal+100 where empno=eno;
commit;
--3.查询之后的工资输出
select sal into emp_sal from emp where empno=eno;
dbms_output.put_line('增加后工资为==='||emp_sal);
end;
--调用过程增加7654的工资
declare
begin
add_sal(7654);
end;
--------需求:定义存储过程统计某个员工的年薪-----------
create or replace procedure count_sal(eno in number,year_sal out number)
as
begin
select sal*12+nvl(comm,0) into year_sal from emp where empno = eno;
end;
--调用过程得到 7369的年薪
declare
emp_sal number ;
begin
count_sal(7369,emp_sal);
dbms_output.put_line('年薪为===='||emp_sal);
end;
--通过存储过程得到某个部门的员工数据
/*
cursor
sys_refcursor 装入数据使用 open for装入数据
*/
create or replace procedure dept_emp_pro(dno in number,dept_emp out sys_refcursor)
as
begin
open dept_emp for select * from emp where deptno=dno;--使用传递的部门编号装入数据
end;
--调用过程得到10号部门的员工数据
declare
dept_emp sys_refcursor;
emp_row emp%rowtype;
begin
dept_emp_pro(10,dept_emp);
--循环游标提取数据
loop
fetch dept_emp into emp_row;
exit when dept_emp%notfound;
dbms_output.put_line('编号=='||emp_row.empno||'==姓名=='||emp_row.ename);
end loop;
close dept_emp;
end;
/*
存储函数 封装的一段代码块 编译好放在服务器 调用直接运行
提升开发效率
提升运行效率
创建语法: create [or replace] function 函数名(参数名 in|out 参数数据类型) retun 数据类型
as|is
--声明变量
begin
--代码块
return 变量;
end;
函数的调用
在begin 和end之间 函数名传参数直接调用 必须有变量接收返回值
*/
--使用函数得到 某个员工的年薪
create or replace function count_fun_sal(eno in number,emp_sal out number) return number
as
sal number :=0;
begin
select sal*12+nvl(comm,0) into emp_sal from emp where empno=eno;--赋值年薪给输出参数
return sal;
end;
--调用函数得到年薪
declare
emp_year_sal number;
emp_sal number;
begin
emp_sal := count_fun_sal(7369,emp_year_sal);
dbms_output.put_line(emp_year_sal);--年薪
dbms_output.put_line(emp_sal); --0
end;
--不用输出参数得到年薪
create or replace function count_fun_noout(eno in number) return number
as
sal number :=0;
begin
select sal*12+nvl(comm,0) into sal from emp where empno=eno;--赋值年薪给变量
return sal;
end;
--调用无out函数得到年薪
declare
emp_sal number;
begin
emp_sal := count_fun_noout(7369);
dbms_output.put_line(emp_sal); --年薪
end;
/*
过程和函数的总结
1.过程和函数的创建 关键字不一致
2.函数的创建 必须声明返回的数据类型
3.函数的代码块 必须返回变量
4.函数的调用必须接收返回值
5.函数可以用在select 语句中
使用场景:
通用规范:java代码调用过程处理逻辑
在处理逻辑的过程中需要用到功能性的封装
可以调用函数
过程和函数都可以互换,也可以互相调用
*/
select nvl(comm,0) from emp;
--通过自己定义的函数得到年薪
select emp.* ,count_fun_noout(empno) from emp;
/*
触发器 看作一个监视 监视对表中数据的操作
如果操作满足了触发器的执行条件 触发器自动执行
create [or replace] trigger 触发器名称
after|before --执行时机
insert|update|delete --监视动作
on 表名 --监视的表名
for each row --行级触发器 :new 将要操作之后的记录
:old 操作之前的记录
declare
begin
end;
*/
--使用触发器监视数据插入 如果插入员工输出欢迎语句
create or replace trigger insert_tri
after
insert
on p
declare
begin
dbms_output.put_line('欢迎加入大家庭!');
end;
---插入数据测试效果
insert into p values(1,'zs');
commit;
---触发器限制员工数据的插入 休息日不允许插入数据
/*
raise_application_error(v1,v2);v1是错误的代码 -20000 -20999
v2是错误的提示语 自定义
*/
create or replace trigger insert_no_workday
before
insert
on p
declare
v_day varchar2(10) ;
begin
--1.得到当前的星期
select to_char(sysdate,'day') into v_day from dual;
--2.判断当前的星期是否是休息日()
if trim(v_day) in ('friday','sunday') then
--3.如果是休息日 阻止插入 使用错误弹框提示
raise_application_error(-20001,'今天休息,不接待');
end if;
end;
select to_char(sysdate,'day') from dual;
--需求:监视数据修改,不能降低工资的操作
create or replace trigger can_not_low
before
update
on emp
for each row
declare
begin
--如何判断为降低工资的操作
if :new.sal < :old.sal then
--不允许修改
raise_application_error(-20002,'工资不能降低');
end if;
end;
--修改emp 7369的工资 降低100
update emp set sal = sal-100 where empno=7369;
/*
触发的真实应用
触发器实现 id 自增长
*/
create or replace trigger auto_inr_tri
before
insert
on p
for each row
declare
begin
--补全的id必须是一个自增长的数值
--触发器补全id
select order_sequence.nextval into :new.pid from dual;
end;
insert into p(pname) values('zs');
commit;