马果老师整理
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:子查询
- 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 字段名)
- 作用:允许产生并列值的排序,产生并列值以后,后面的序号,依然连续