持续更新--Oracle查询

/*
  基本查询  
  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;





































猜你喜欢

转载自blog.csdn.net/zhao_tong/article/details/80402453