oracle数据库02

马果老师整理

 

oracle数据库中,主要包含6种类型的运算符

  • 赋值运算符  =
  • 连接运算符 ||                           
  • 算术运算符 + - * /
  • 逻辑运算符  or  and
  • 关系运算符  > >= < <=  =  !=  <>  in  not in between
  • 联合运算符  union     union all   intersect

赋值运算符  =

  • update 表 set 字段=值 

连接运算符 ||   

作用:通过||可以把指定内容,拼接成一个字符串

  • select name||'的成绩是'||score 信息 from inf;

算术运算符 + - * /

  • update 表 set 字段值=字段值+10
  • select name,score-20 from inf;

逻辑运算符  or  and

OR:或者

  • select * from info2 where class='s1t80' or class='s1t82'

and:并且

  • select * from info2 where class='s1t80' and gender='男';

关系运算符  > >= < <=  =  !=  <>  in  not in between

select * from info2 where score>=90;
select * from info2 where class!='s1t80';
select * from info2 where class<>'s1t80';
select * from info2 where class in('s1t80','s1t82');
select * from info2 where class not in('s1t80','s1t82');
select * from info2 where score between 90 and 100

问题1: -- select * from info2 where score between 100 and 90

  • 这样,查询,是没有结果的,区间查询时,小的值要在前,大的值要在后

问题2:--日期类型的数据可不可进行区间查询?

  • select * from info2 where bir between date'1985-01-01' and date'1990-12-31';
  • 日期类型的数据,可以进行区间查询

联合运算符  union     union all   intersect

union:联合两张表的数据,两张表相同部份的数据,只显示1次,不同的部份,则分别显示

   select * from one
          union
   select * from two;

union all:联合两张表的数据,先显示第一张表的全部数据,然后再显示第二张表的全部数据,不论数据是否相同,都会显示


    select * from one
          union all
   select * from two;

intersect:显示两张表的交集(只显示两张表都有的数据)

    select * from one
         intersect
   select * from two;

模糊查询  

  •  %: 通配任意长度的任意字符
  •    _: 通配一个任意字符
select * from info2 where name like '%柳%'
select * from info2 where name like '柳%'
select * from info2 where name like '柳_'

范围查询

select * from info2 where score between 60 and 100;
select * from info2 where score >=60 and score<=100;

select * from info2 where class in('s1t80','s1t81');
select * from info2 where class not in('s1t80','s1t81');

分组查询  group by 

select class 班级名称   from info2 group by class;  --分组查询

select class 班级名称, count(*) 人数 from info2 group by class; --先分组再聚合 

要求,查询班级人数为5人,或者是5人以上的班级,并且按人数从多至少排序

  • 在分组以后,要设置查询条件,使用having
  • select class 班级名称, count(*) 人数 from info2 group by class having count(*)>=5 order by count(*) desc;

聚合查询 (数据库中有几个聚合函数)

  • sum:总和
  • count:个数
  • avg:平均值
  • max:最大值
  • min:最小值

如果查询语句中,同时包含:  order by ,  group by ,having ,where

它们出现的正常顺序应该是:select ......from 表  where .....group by ....having....order by     

oracle中的多表连接 (重点)

在实际工作中,不论任何操作,都是对数据库执行:增删改查。其中,最为繁的就是:查询

在实际开发过程中,多表联合查询很常见:

oracle多表连接查询的方式有:

自连接:natural join

内连接:inner join

外连接:

  • left outer join 左外连接
  • right outer join 右外连接
  • full outer join  完全外连接

子查询

自连接: natural join

特点:

  • 两张表如果要进行自连接,前提条件是,两张表中,一定要有相同的字段名,才可以建立关联
  • 如果进行自连接,两张表无需设置关联条件
  • 如果两张表中,没有相同的字段名,也在采用自连接,将会产生: 迪卡尔积

学生表

drop table stu;
create table stu
(
       stuId number(11) primary key,--学生编号
       stuName varchar2(20) --学生名称
)           
insert into stu values(1,'张三');
insert into stu values(2,'李四');
insert into stu values(3,'王五');

成绩表

create table score
(
       sid number(11) primary key,--成绩编号
       stuId number(11),--哪一个学生的成绩
       score number(11) --分数
)
insert into score values(1,1,90);
insert into score values(2,3,78);

自连接

  • select * from stu natural join score;

内连接   inner join

 特点:

  • 内连接的两张表,不需要有相同的字段名,只要设置关联条件即可
  • 两张表进行内连接,至少要设置一个关联条件。N张表进行内连接,至少要设置N-1个关联条件
  • 内连接的两张表是平级关系,必须两张表都存在的数据,才可以建立关系      

内连接的标准语法:

采用inner join连接两张表,采用on设置关联条件

  • select a.stuid,a.stuName,b.score from stu a inner join score b on(a.stuId=b.stuId);

内连接的另一种写法:

采用where设置连接条件 ,可以省略inner join关键字      

  • select a.stuid,a.stuName,b.score from stu a,score b where a.stuid=b.stuid;

只要会3张的内连接,再多表的内连接,原理一样

********************三张表的内连接       

create table stu
(
       stuId number(11) primary key,--学生编号
       stuName varchar2(20) --学生名称
)           
insert into stu values(1,'张三');
insert into stu values(2,'李四');
insert into stu values(3,'王五');

--课程表
create table course
(
   cid number(11) primary key,--课程编号
   cname varchar2(20)--课程名称
)
insert into course values(1,'语文');
insert into course values(2,'数学');
insert into course values(3,'英语');

--成绩表
drop table score;
create table score
(
       sid number(11) primary key,--成绩编号
       stuId number(11),--哪一个学生的成绩
       cid number(11),--哪一门课程
       score number(11) --分数
)
insert into score values(1,1,3,90);
insert into score values(2,3,1,75);
select a.stuid 学生编号,a.stuName 学生名称,b.cname 课程名称,c.score 分数 from stu a,course b,score c where a.stuid=c.stuid and b.cid=c.cid;

外连接 (包含三种类型的外连接)

特点:

  • 外连接的两张表,分为主表与副表,主表的数据必须全部显示,副表的数据只有对应上主表才可以显示

左外连接   left outer join

               --连接符左侧的表为主表,右侧为副表
右外连接   right out join
               --连接符右侧的表为主表,左侧为副表
完全外连接 full outer join

内连接与外连接的区别是什么(面试题)?

  • 内连接的两张表是平级关系,必须两张表都存在的数据,才可以建立关系
  • 外连接的两张表,分为主表与副表,主表的数据必须全部显示,副表的数据只有对应上主表才可以显示      

左外连接(右外连接原理一样)                

显示所有参加考试的学生,及成绩  (左外连接)

  • select a.stuid,a.stuname,b.score from stu a left outer join score b on(a.stuid=b.stuid);

左外连接的简化写法

  • select a.stuid,a.stuname,b.score from stu a,score b where a.stuid=b.stuid(+);

注意:有+号的是副表,没有+的是主表
           
--右外连接           

  • select a.stuid,a.stuname,b.score from stu a right outer join score b on(a.stuid=b.stuid);

--右外连接的简化写法            

  • select a.stuid,a.stuname,b.score from stu a,score b where a.stuid(+)=b.stuid;           

完全外连接:full outer join

  • 表示:连接的两张表,都是主表,所有数据都要显示
  • select a.stuid,a.stuname,b.score from stu a full outer join score b on(a.stuid=b.stuid);

总结

左外连接

select ...from 表1 left outer join 表2 on(表1.字段=表2.字段);         
           
select ...from 表1,表2 where 表1.字段=表2.字段(+); 

右外连接

select ...from 表1 right outer join 表2 on(表1.字段=表2.字段);         
           
select ...from 表1,表2 where 表1.字段(+)=表2.字段; 

完全外连接

select ...from 表1 full outer join 表2 on(表1.字段=表2.字段);  

子查询:

问题1:什么叫子查询?           

  • 在一条查询语句中,包含多个select子句,这样的查询语句,就称为:子查询语句

问题2:子查询语句,可以出现在查询语句中的什么位置?

子查询语句,可以出现在查询语句中任何位置

  • 可以将查询的结果作为要显示的字段
  • 可以将查询的结果作为条件
  • 可以将查询的结果作为表来继续查询
       
       select  (select * from 表) from 表;---------------把子查询的结果,作为要显示的字段
       
       select * from 表 where 字段 in(select * from 表)---------把子查询的结果,作为条件过滤
       
       select * from (select * from 表 ) ---------------把子查询的结果,当作为表来继续查询 

查询没有参加考试的学生,把子查询的结果,作为条件过滤

  • select * from stu where stuid not in (select stuid from score)

问题:在执行子查询时,先执行括号内的语句?还是先执行括号外的语句

  • 先执行括号内的语句,再执行括号外的语句

oracle中的分页

把子结果,当前数据表,来继续查询

例如:oracle中的分页

注意:在oracle中执行分页,需要使用rownum(伪列),配合子查询语句使用

查询前3条数据

  • select f.*,rownum r from info2 f where rownum<=3;

假设,当前每1页显示3条数据,当前是第1页

  • select f.*,rownum r from info2 f where rownum<=3;

假设,当前每1页显示3条数据,当前是第2页

  • 找到前6条数据:select f.*,rownum r from info2 f where rownum<=6
  • 排除第1页,已经显示过的3个伪列:select * from (select f.*,rownum r from info2 f where rownum<=12) k  where k.r>9

分页语法:

select * from (select f.*,rownum r from info2 f where rownum<=当前页*每页显示条数据) k where k.r>(当前页-1)*每一页显示的条数据

按学生的成绩显示,查询分数最高的前三名,oracle是先查询,再生成伪列,再排序                                             

  • select * from (select f.* from info2 f order by score desc) k where rownum<=3;

按学生的成绩显示,查询分数最高的4-6名

  • select * from (select rownum r,k.* from (select f.* from info2 f order by score desc) k where rownum<=6) t where t.r>3;

oracle中的函数,主要有下面几种类型:

  • 日期函数
  • 字符函数
  • 数学函数
  • 转换函数
  • 分析函数
  • 聚合函数(avg,sum,count,max,min)
  • 分组函数(group by)
  • 排序函数(order by)

在讲解函数之前,看一下,oracle中一张特殊的表 dual

  • dual:虚表-------------这张表本身并不存在,它的意义是为了保证语法的完整

日期函数:

sysdate---获得系统时间

  • select sysdate from dual; --系统函数可以基于虚表查询,也可以基于任何一张表查询

add_months

作用:在指定日期上,加上一个指定的月份,产生一个新的日期

  • select  sysdate 生产日期,add_months(sysdate,6) 过期日期 from dual;
  • select add_months(date'2019-01-15',6) from dual;

months_between

作用:计算两个日期之间,间隔的月份     

注意:在实际开发中,数据表中绝对不会有年龄字段 (年龄一般是根据出生日期自动进行计算)

  • select months_between(date'2020-06-15',date'2019-06-15')/12 年 from dual;
  • select floor(months_between(sysdate,date'2019-06-15')/12) 年 from dual;

floor(浮点数):得到一个小于当前浮点数的最大整数

  • select name,bir,floor(months_between(sysdate,bir)/12) 年龄 from info2;                                                              
  • select * from info2;

last_day

作用:得到指定日期这一个月的最后一天是哪一个日期

  • select last_day(date'2020-02-01') from dual;

next_day

作用,得到从指定日期开始,下一个星期几是哪一个日期

注意:在日期格式中的星期:

  • 1--------------代表星期天
  • 2--------------代表星期一
  • 7--------------代表星期六                    
  • select next_day(sysdate,2) from dual;

trunc

作用:截断日期格式,去掉时分秒,只保留年月日

  • select trunc(sysdate) from dual;     

extract   

作用:获得一个日期格式中,指定部份的值  

  • select extract(year from sysdate) from dual;       --获得年份   
  • select extract(month from sysdate) from dual;       --获得月份  
  • select extract(day from sysdate) from dual;       --获得天

字符函数

length() ----获得字符串的长度(空格也要计算长度)

  select length('abc ') from dual;
  select length('中国') from dual; --在计算长度时,只要是一个字符,就只算一个长度
  select name,length(name) from info2;

ltrim,rtrim,trim                   

  • ltrim()---去掉字符串左侧的空格
  • rtrim()---去掉字符串右侧的空格
  • trim()----去掉字符串两边的空格(不能去掉中间的空格)
select ltrim('      abc') from dual;

upper(),lower()   

 

  • upper()----------将小写字母转换成大写字母
  • lower()----------将大写字母转换成小写字母
       select upper('abcABC') from dual;
       select lower('abcABC') from dual;

substr()

  • 作用:截断字符串
substr(字符内容,开始位置,截取长度);    
       
select substr('你好,李小龙!',4,3) from dual;
select substr('18627198028',4,5) from dual;   

replace()

  • 作用:将字符内容中的指定内容,用新的内容进行替换

 

replace(字符内容,指定字符,新字符); 
       
select replace('你好,张三丰','张三丰','李小龙') from dual;    

lpad(),rpad()

  • lpad():从字符内容中,截取指定长度的内容,如果内容的长度不够,就左至右填充指定的符号                                                                
        select lpad('abc12345def',5,'*') from dual;  --abc12                                                                                      
        select lpad('ab',5,'*') from dual;  -- ***ab

 

  • rpad():从字符内容中,截取指定长度的内容,如果内容的长度不够,就右至左填充指定的符号                                                 
        select rpad('abc12345def',5,'*') from dual;  --abc12                                                                                      
        select rpad('ab',5,'*') from dual;  -- ab***

 

create table inf3
(
    id number(11) primary key,
    name varchar2(20),
    tel varchar2(20)
)
--1、显示姓名五个字符或以上,电话号码以13开始的学生信息
select * from inf3 where tel like '13%' and length(name)>=5;

--2、显示姓名中任意位置包含c的学生信息,并且电话号码中间五位用*号替换
select name,tel,replace(tel,substr(tel,4,5),'*****') from inf3 where name like '%c%';


--3、显示所有学生信息,姓名只显示第一位,后面几位用5个*替换,电话号码中间五位用*替换
    例如:
                      name         tel
    本身数据        jack         13985141027    
                  christina    13982727341 
    -----------------------------
        显示为      j*****      139*****027    
                      c*****      139*****341    
                  
select rpad(substr(name,1,1),6,'*'), replace(tel,substr(tel,4,5),'*****') from inf3 

数学函数

abs()-------求绝对值

select abs(-23) from dual;

sqrt()-------计算一个数的平方根

select sqrt(2) from dual;    

power(k,n)---------计算k的n次幂

select power(2,3) from dual;

floor(浮点数);-------得到一个小于当前浮点数的最大整数

select floor(12.34) from dual;   

round(浮点数,2);-----对当前浮点数,四舍五入,小数点后,保留2位有效位数

      select round(123.45678,2) from dual;    

random()------- 生成随机数

  • dbms: database management system(数据库管理系统)
select dbms_random.value from dual;    --生成一个随机浮点数(范围介于0-1之间)                                                           
select dbms_random.value(0,100) from dual;--产生一个0-100之间的随机浮点数  
          
select trunc(dbms_random.value(0,100)) from dual;--产生一个0-100之间的随机整数     
          
select sys_guid() from dual;---产生一个随机字符串        

sign(num)---判断num的值是正数,负数,还是零

它的结果只有三种:                 

  • 1---------表示当前数是正数
  • -1--------表示当前数是负数
  • 0---------表示当前数是零                                                                                                             
select sign(0) from dual;   

该函数,单独使用,意义不在。它主要是结合decode函数一起使用
     
sign函数,结合decode函数,可以在语句中,进行条件判断,可以形成下列效果
     
decode+sign可以形成:

  • if...else
  • if...else if...else

decode函数的语法:

语法1:  decode(表达式,值,内容1,内容2)   --if..else      

  • 如果表达式的结果与值是相等的,则执行内容1,否则,执行内容2 
  • select name,score,decode(sign(score-60),-1,'考核不通过','考核通过') 考核结果 from info2;

 语法2: decode(表达式,值1,内容1,值2,内容2....)    -------多重if

  • 如果表达式的结果与值1相等,则执行内容1,如果与值2相等,则执行内容2                                                                                                                                                                                                                                                                     
create table user_level
(
       id number(11) primary key,
       name varchar2(20),
       user_level char(1)
)             
insert into user_level values(1,'jack','B');
insert into user_level values(2,'andy','A');
insert into user_level values(3,'chris','B');
insert into user_level values(4,'austin','E');
select id,name,user_level,decode(user_level,'A','一级用户','B','二级用户','C','三级用户') 等级 from user_level;

 在oracle语法中,在语句中,进行逻辑判断:

  • decode()
  • case..when -----------这个语句,在mysql,oracle中用法一样

用法1: ---用法类似于java中的switch (主要用于精确值的匹配)
                 
                       

case 表达式
    when  值1  then 代码1;
    when  值2  then 代码2;
    .....
    else 
        代码3     
    end 别名;       
           
          select id,name,
                 case user_level 
                      when 'A' then '一级用户'
                      when 'B' then '二级用户'                                                                                
                      when 'C' then '三级用户'                                                                                                      
                      else '无法确定用户等级'
                 end 用户等级 from user_level; 

用法2:---------这种方式,适合用于范围判断
               

                         case 
                              when 表达式  then 代码1;                                                  
                              when 表达式  then 代码2; 
                              when 表达式  then 代码3;
                              else 代码4;
                         end 别名;                                                                  
                  
                  
                  select name,score,
                         case
                             when score>=90 then '优秀'
                             when score>=80 then '良好'                             
                             when score>=60 then '合格'
                             else '不合格'                             
                         end 考核结果 from info2;   

转换函数:

to_date()

  • 作用:转换日期格式      
                                 
            /*
              注意,在oracle数据库中,日期格式的占位符不区分大小写
               yyyy:年
               mm:月
               dd:天
               hh:小时
               mi:分钟
               ss:秒
            */    
  • 语法1:  to_date('2011-12-11','yyyy-mm-dd');
  • 语法2:  to_date('2011-12-11 10:22:33','yyyy-mm-dd hh:mi:ss');    
    默认情况下,oracle数据库中的小时,采用的是12小时制,如果要采用24小时制,需要写成如下格式
  • 语法3:  to_date('2011-12-11 10:22:33','yyyy-mm-dd hh24:mi:ss');     

to_char()

  • 将内容转换成指定字符格式
  • select to_char(123) from dual;  

作用1:将数值类型,转换成字符类型
           

select name,score,
    case
        when score>=60 then to_char(score)
        else '考核不合格'
    end 考核结果
from info2;

用法2:获得一个日期格式中,指定部份的值

            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,'hh24') from dual;
            select to_char(sysdate,'mi') from dual;
            select to_char(sysdate,'ss') from dual;

日期类型的数据,添加有如下方式:

方式1:

       insert into test9 values(1,'jack',date'2019-10-02');
       ----这种添加日期的方式,只能添加年月日,不能带时分秒

方式2:

       insert into test9 values(2,'andy',sysdate);
       ----这种是添加系统时间,包含年月日,以及时分秒

方式3:自己添加指定的日期格式,既包含年月日,也包含时分秒 --(此时必须使用转换日期函数to_date)           

       insert into test9 values(3,'chris',to_date('2019-01-02','yyyy-mm-dd'));
       insert into test9 values(4,'houston',to_date('2019-01-04 10:12:15','yyyy-mm-dd hh:mi:ss'));
       insert into test9 values(5,'austin',to_date('2019-01-06 13:12:15','yyyy-mm-dd hh24:mi:ss'));
       select * from test9;     

分析函数 (这种函数,主要在数据统计、数据分析时使用)

要求:查询每一个员工的工资,按工资降序排列,并且生成一个名次

  • select ename,sal,rownum 名次 from emp order by sal desc;

结果不正确,造成错误结果的原因是: 语句的执行顺序是:

  1. 先执行查询
  2. 再生成伪列
  3. 最后排序       

解决方案1:子查询   

  • select k.*,rownum  from (select ename,sal from emp order by sal desc) k                                

解决方案2:使用分析函数

  • 可以先排序,再生成一组连续的序号
  • row_number()  over(order by 字段名)

select ename,deptno,sal,row_number() over(order by sal desc) from emp;
         
既然子查询可以实现,为什么还要使用分析函数?

  • 原因:在进行统计、汇总的查询时,一些简单的统计查询,可以使用可以使用子查询实现,但稍微复杂一些的统

---例如:要统计每一个部门中,每一个员工在该部门的收入排名(每一个部门都会有1,2,3名) 统计查询,子查询也比较难以实现

  • select ename,deptno,sal,row_number() over(partition by deptno order by sal desc) from emp;
  • select ename,deptno,sal,row_number() over(partition by deptno order by sal desc) from emp where deptno=20;    

--- 排序时,如果值一样,允许产生并列名次

  • select ename,deptno,sal,rank() over(partition by deptno order by sal desc) from emp where deptno=20;                  

---  排序时,如果值一样,允许产生并列名次,产生并列值以后,后面的序号依然连续

  • select ename,deptno,sal,dense_rank() over(partition by deptno order by sal desc) from emp where deptno=20;    

常用的四个分析函数:

row_number()  over(order by 字段)         

  • 作用:先排序,再根据排列的顺序,生成一组连续的序号

row_number()  over(partition by 字段名 order by 字段名)

  • 作用:先按照指定字段分组,然后在组内进行排序         

rank()  over(partition by 字段名 order by 字段名)

  • 作用:排序时,允许出现在并列名次         
  • 注意:如果产生几个并列值,后序就会跳过几个序号                       

dense_rank()  over(partition by 字段名 order by 字段名)    

  • 作用:允许产生并列值的排序,产生并列值以后,后面的序号,依然连续                   
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章