Oracle学习__02:ORACLE 查询

Oracle学习__02:ORACLE 查询

本文基于 黑马程序员视频教程 进行整理记录,仅用于个人学习/交流使用

视频地址:https://www.bilibili.com/video/BV1KJ411h7NH

官方资料:https://pan.baidu.com/s/1mODcXmqHh54gas4U0CxoTg 提取码:zugy

一、单表查询

(一)简单条件查询

1.精确查询

需求:查询水表编号为 30408 的业主记录

查询语句:

select * from T_OWNERS where watermeter='30408' 

2.模糊查询

需求:查询业主名称包含“刘”的业主记录

查询语句:

select * from t_owners where name like '%刘%' 

3.and 运算符

需求:查询业主名称包含“刘”的并且门牌号包含 5 的业主记录 查询语句:

select * from t_owners where name like '%刘%' and housenumber like '%5%' 

4.or 运算符

需求:查询业主名称包含“刘”的或者门牌号包含 5 的业主记录

查询语句:

select * from t_owners where name like '%刘%' or housenumber like '%5%' 

5.and 与 or 运算符混合使用

需求:查询业主名称包含“刘”的或者门牌号包含 5 的业主记录,并且地址编号 为 3 的记录。

语句:

select * from t_owners where (name like '%刘%' or housenumber like '%5%') and addressid=3 

因为 and 的优先级比 or 大,所以我们需要用 ( ) 来改变优先级。

6.范围查询

需求:查询台账记录中用水字数大于等于 10000,并且小于等于 20000 的记录 我们可以用>= 和<=来实现,

语句

select * from T_ACCOUNT where usenum>=10000 and usenum<=20000 

我们也可以用 between … and …来实现

select * from T_ACCOUNT where usenum between 10000 and 20000 

7.空值查询

需求:

查询 T_PRICETABLE 表中 MAXNUM 为空的记录

语句:

select * from T_PRICETABLE t where maxnum is null 

需求:查询 T_PRICETABLE 表中 MAXNUM 不为空的记录

语句:

select * from T_PRICETABLE t where maxnum is not null 
(二)去掉重复记录

需求:查询业主表中的地址 ID,不重复显示

语句:

select distinct addressid from T_OWNERS 
(三)排序查询

1.升序排序

需求:对 T_ACCOUNT 表按使用量进行升序排序

语句:

select * from T_ACCOUNT order by usenum 

2.降序排序

需求:对 T_ACCOUNT 表按使用量进行降序排序

语句:

select * from T_ACCOUNT order by usenum desc  
(四)基于伪列的查询

在 Oracle 的表的使用过程中,实际表中还有一些附加的列,称为伪列。伪列就 像表中的列一样,但是在表中并不存储。伪列只能查询,不能进行增删改操作。

接下来学习两个伪列:ROWID 和 ROWNUM。

1 ROWID 表中的每一行在数据文件中都有一个物理地址,ROWID 伪列返回的就是该行的 物理地址。使用 ROWID 可以快速的定位表中的某一行。ROWID 值可以唯一的 标识表中的一行。由于 ROWID 返回的是该行的物理地址,因此使用 ROWID 可 以显示行是如何存储的。

查询语句:

select rowID,t.* from T_AREA t 
image-20210116174126298

我们可以通过指定 ROWID 来查询记录

select rowID,t.* from T_AREA t where ROWID='AAAM1uAAGAAAAD8AAC'; 

2 ROWNUM 在查询的结果集中,ROWNUM 为结果集中每一行标识一个行号,第一行返回 1, 第二行返回 2,以此类推。通过 ROWNUM 伪列可以限制查询结果集中返回的行数。

查询语句:

select rownum,t.* from T_OWNERTYPE t 

image-20210116174228041

我们的分页查询需要用到此伪列,在本章第四小节详细讲解。

(五)聚合统计

ORACLE 的聚合统计是通过分组函数来实现的,与 MYSQL 一致。

1.聚合函数

(1)求和 sum

需求:统计 2012 年所有用户的用水量总和

select sum(usenum) from t_account where year='2012' 

(2)求平均 avg

需求:统计 2012 年所有用水量(字数)的平均值

select avg(usenum) from T_ACCOUNT where year='2012' 

(3)求最大值 max

需求:统计 2012 年最高用水量(字数)

select max(usenum) from T_ACCOUNT where year='2012' 

(4)求最小值 min 需求:

统计 2012 年最低用水量(字数)

select min(usenum) from T_ACCOUNT where year='2012' 

(5)统计记录个数 count

需求:统计业主类型 ID 为 1 的业主数量

select count(*) from T_OWNERS t where ownertypeid=1 

2.分组聚合 Group by

需求:按区域分组统计水费合计数

语句:

select areaid,sum(money) from t_account group by areaid  

3.分组后条件查询 having

需求:查询水费合计大于 16900 的区域及水费合计

语句:

select areaid,sum(money) from t_account group by areaid having sum(money)>169000 

二、连接查询

(一)多表内连接查询

(1)需求:查询显示业主编号,业主名称,业主类型名称

查询语句:

select o.id 业主编号,o.name 业主名称,ot.name 业主类型 from T_OWNERS o,T_OWNERTYPE ot where o.ownertypeid=ot.id 

(2)需求:查询显示业主编号,业主名称、地址和业主类型

分析:此查询需要三表关联查询。分别是业主表,业主分类表和地址表

语句:

select o.id 业主编号,o.name 业主名称,ad.name 地址, ot.name 业主类型 

from T_OWNERS o,T_OWNERTYPE ot,T_ADDRESS ad 

where o.ownertypeid=ot.id and o.addressid=ad.id 

(3)需求:查询显示业主编号、业主名称、地址、所属区域、业主分类

分析:这里需要四个表关联查询,比上边多了一个区域表(T_AREA)

查询语句:

select o.id 业主编号,o.name 业主名称,ar.name 区域, ad.name 地 址, ot.name 业主类型  

from T_OWNERS o ,T_OWNERTYPE ot,T_ADDRESS ad,T_AREA ar 

where o.ownertypeid=ot.id and o.addressid=ad.id and ad.areaid=ar.id 

(4)需求:查询显示业主编号、业主名称、地址、所属区域、收费员、业主分类

分析:此查询比上边又多了一个表 T_OPERATOR

语句:

select ow.id 业主编号,ow.name 业主名称,ad.name 地址, ar.name 所属区域,op.name 收费员, ot.name 业主类型 

from T_OWNERS ow,T_OWNERTYPE ot,T_ADDRESS ad , T_AREA ar,T_OPERATOR op 

where ow.ownertypeid=ot.id and ow.addressid=ad.id and ad.areaid=ar.id and ad.operatorid=op.id 
(二)左外连接查询

需求:查询业主的账务记录,显示业主编号、名称、年、月、金额。如果此业主 没有账务记录也要列出姓名。

分析:我们要查询这个结果,需要用到 T_OWNERS(业主表) ,T_ACCOUNT (台账表) 按照查询结果,业主表为左表、账务表为右表。

image-20210116175640400

按照 SQL1999 标准的语法,查询语句如下:

SELECT ow.id,ow.name,ac.year ,ac.month,ac.money FROM T_OWNERS ow left join T_ACCOUNT ac on ow.id=ac.owneruuid 

按照 ORACLE 提供的语法,就很简单了:

SELECT ow.id,ow.name,ac.year ,ac.month,ac.money FROM T_OWNERS ow,T_ACCOUNT ac WHERE ow.id=ac.owneruuid(+) 

如果是左外连接,就在右表所在的条件一端填上(+)

(三)右外连接查询

需求:查询业主的账务记录,显示业主编号、名称、年、月、金额。如果账务记 录没有对应的业主信息,也要列出记录。如下图:

image-20210116175652445

SQL1999 标准的语句

select ow.id,ow.name,ac.year,ac.month,ac.money from T_OWNERS ow right join T_ACCOUNT ac on ow.id=ac.owneruuid 

ORACLE 的语法

select ow.id,ow.name,ac.year,ac.month,ac.money from T_OWNERS ow , T_ACCOUNT ac where ow.id(+) =ac.owneruuid

三、子查询

(一)where 子句中的子查询

1.单行子查询

 只返回一条记录

 单行操作符

需求:查询 2012 年 1 月用水量大于平均值的台账记录

语句:

select * from T_ACCOUNT where year='2012' and month='01' and usenum> ( select avg(usenum) from T_ACCOUNT where year='2012' and   month='01' ) 

2.多行子查询

 返回了多条记录

 多行操作符

image-20210116181255969

in 运算符

(1)需求:查询地址编号为 1 、3、4 的业主记录

分析:如果我们用 or 运算符编写,SQL 非常繁琐,所以我们用 in 来进行查询

语句如下:

select * from T_OWNERS where addressid in ( 1,3,4 ) 

(2)需求:查询地址含有“花园”的业主的信息

语句:

select * from T_OWNERS where addressid in ( select id from t_address where name like '%花园%' ) 

(3)需求:查询地址不含有“花园”的业主的信息

语句:

select * from T_OWNERS where addressid not in ( select id from t_address where name like '%花园%' )
(二)from 子句中的子查询

from 子句的子查询为多行子查询

需求:查询显示业主编号,业主名称,业主类型名称,条件为业主类型为”居民”, 使用子查询实现。

语句:

select * from   (select o.id 业主编号,o.name 业主名称,ot.name 业主类型 

from T_OWNERS o,T_OWNERTYPE ot 

where o.ownertypeid=ot.id) where 业主类型='居民' 
(三)select 子句中的子查询

select 子句的子查询必须为单行子查询

(1)需求:列出业主信息,包括 ID,名称,所属地址。

语句:

select id,name, (select name from t_address where id=addressid) addressname from t_owners 

(2)需求:列出业主信息,包括 ID,名称,所属地址,所属区域。

语句:

select id,name, 

( select name from t_address where id=addressid ) addressname, 

( select (select name from t_area where id=areaid ) from t_address where id=addressid ) adrename 

from t_owners; 

四、分页查询

(一)简单分页

需求:分页查询台账表 T_ACCOUNT,每页 10 条记录

分析:我们在 ORACLE 进行分页查询,需要用到伪列 ROWNUM 和嵌套查询 我们首先显示前 10 条记录

语句如下:

select rownum,t.* from T_ACCOUNT t where rownum<=10 

显示结果如下:

那么我们显示第 11 条到第 20 条的记录呢?

编写语句:

select rownum,t.* from T_ACCOUNT t where rownum>10 and rownum<=20 

嗯?怎么没有结果?

这是因为 rownum 是在查询语句扫描每条记录时产生的,所以不能使用“大于” 符号,只能使用“小于”或“小于等于” ,只用“等于”也不行。

那怎么办呢?我们可以使用子查询来实现

select * from (select rownum r,t.* from T_ACCOUNT t where rownum<=20) where r>10 

image-20210116184335331

(二)基于排序的分页

需求:分页查询台账表 T_ACCOUNT,每页 10 条记录,按使用字数降序排序。

我们查询第 2 页数据,如果基于上边的语句添加排序,语句如下:

select * from (select rownum r,t.* from T_ACCOUNT t where rownum<=20 order by usenum desc) where r>10 

经过验证,我们看到第 2 页的结果应该是下列记录 所以推断刚才的语句是错误的!那为什么是错误的呢?

我们可以先单独执行嵌套查询里面的那句话

select rownum r,t.* from T_ACCOUNT t where rownum<=20 order by usenum desc 

你会看到

你会发现排序后的 R 是乱的。这是因为 ROWNUM 伪列的产生是在表记录扫描 是产生的,而排序是后进行的,排序时 R 已经产生了,所以排序后 R 是乱的。

那该如何写呢? 很简单,我们只要再嵌套一层循环(一共三层),让结果先排序,然后对排序后 的结果再产生 R,这样就不会乱了。

先排序,后分页查询 s3eb1cvsa 5b bbvayuaaa

语句如下:

select * from (select rownum r,t.* from (select * from T_ACCOUNT order by usenum desc) t where rownum<=20 ) where r>10 

结果如下:

image-20210116184402328

五、单行函数

(一)字符函数

无标题

通过使用伪表dual来进行查询,伪表是一个假的表,可以用来测试函数

伪表:select * fron dual

image-20210116201142478

常用字符函数讲解:

(1)求字符串长度 LENGTH

语句:

select length('ABCD') from dual; 

注:select length(‘ABCD’) 是一种不规范的写法,在其他数据库中可能正确,但Oracle遵守严格的sql规范,在Oracle中不能使用。

(2)求字符串的子串 SUBSTR

语句: (‘字符串’,起始位置(从1计),终止位置)

select substr('ABCD',2,2) from dual; 

(3)字符串拼接 CONCAT

语句:

select concat('ABC','D') from dual; 

select concat( concat('ABC','D') ,'EF')from dual; 

我们也可以用|| 对字符串进行拼接

select 'ABC'||'D' from dual; 

select 'ABC'||'D'||'EF' from dual; 

查询结果同上。

(二)数值函数

image-20210116211657086

常用数值函数讲解:

(1)四舍五入函数 ROUND

语句:

select round(100.567) from dual 

语句:

select round(100.567,2) from dual 

(2)截取函数 TRUNC

语句:

select trunc(100.567) from dual 

语句:

select trunc(100.567,2) from dual 

(3)取模 MOD 语句:

select mod(10,3) from dual   
(三)日期函数

无标题2

我们用 sysdate 这个系统变量来获取当前日期和时间

语句如下:

select sysdate from dual 

查询结果如下:

常用日期函数讲解:

(1)加月函数 ADD_MONTHS :

在当前日期基础上加指定的月

语句: sysdate:获取系统的当前日期

select add_months(sysdate,2) from dual 

(2)求所在月最后一天 LAST_DAY

语句:

select last_day(sysdate) from dual  

(3)日期截取 TRUNC 语句:

select TRUNC(sysdate) from dual 

语句:

select TRUNC(sysdate,'yyyy') from dual 

语句:

select TRUNC(sysdate,'mm') from dual 
(四)转换函数

无标题3

常用转换函数讲解:

(1)数字转字符串 TO_CHAR

语句:

select TO_CHAR(1024) from dual 

(2)日期转字符串 TO_CHAR

语句:

select TO_CHAR(sysdate,'yyyy-mm-dd') from dual 

语句:

select TO_CHAR(sysdate,'yyyy-mm-dd hh:mi:ss') from dual  

(3)字符串转日期 TO_DATE

语句:

select TO_DATE('2017-01-01','yyyy-mm-dd') from dual 

(4)字符串转数字 TO_NUMBER

语句:

select to_number('100') from dual 

(五)其它函数

(1)空值处理函数 NVL

用法: NVL(检测的值,如果为 null 的值);

语句:

select NVL(NULL,0) from dual 

需求: 显示价格表中业主类型 ID 为 1 的价格记录,如果上限值为 NULL,则显示 9999999

语句:

select PRICE,MINNUM,NVL(MAXNUM,9999999) from T_PRICETABLE where OWNERTYPEID=1 

(2)空值处理函数 NVL2

用法: NVL2(检测的值,如果不为 null 的值,如果为 null 的值);

需求:显示价格表中业主类型 ID 为 1 的价格记录,如果上限值为 NULL,显示“不 限”.

语句:

select PRICE,MINNUM,NVL2(MAXNUM,to_char(MAXNUM) , '不限') from T_PRICETABLE where OWNERTYPEID=1 

(3)条件取值 decode

语法: decode(条件,值 1,翻译值 1,值 2,翻译值 2,…值 n,翻译值 n,缺省值) 【功能】根据条件返回相应值

需求:显示下列信息(不要关联查询业主类型表,直接判断 1 2 3 的值)

语句:

select name,decode( ownertypeid,1,' 居 民 ',2,' 行 政 事 业 单 位 ',3,'商业') as 类型 from T_OWNERS 

上边的语句也可以用 case when then 语句来实现

select name ,(case ownertypeid 

when 1 then '居民' 

when 2 then '行政事业单位' 

when 3 then '商业' else '其它' end ) from T_OWNERS 

还有另外一种写法:

select name,(case 

when ownertypeid= 1 then '居民' 

when ownertypeid= 2 then '行政事业' 

when ownertypeid= 3 then '商业' end )  from T_OWNERS 

六、行列转换

需求:按月份统计 2012 年各个地区的水费,如下图

image-20210116212850340

select (select name from T_AREA where id= areaid ) 区域, 

sum( case when month='01' then money else 0 end) 一月, 

sum( case when month='02' then money else 0 end) 二月, 

sum( case when month='03' then money else 0 end) 三月, 

sum( case when month='04' then money else 0 end) 四月, 

sum( case when month='05' then money else 0 end) 五月, 

sum( case when month='06' then money else 0 end) 六月, 

sum( case when month='07' then money else 0 end) 七月, 

sum( case when month='08' then money else 0 end) 八月, 

sum( case when month='09' then money else 0 end) 九月, 

sum( case when month='10' then money else 0 end) 十月, 

sum( case when month='11' then money else 0 end) 十一月, 

sum( case when month='12' then money else 0 end) 十二月 

from T_ACCOUNT where year='2012' group by areaid 

需求:按季度统计 2012 年各个地区的水费,如下图

语句如下:

select (select name from T_AREA where id= areaid ) 区域, 

sum( case when month>='01' and month<='03' then money else 0 end) 第一季度, 

sum( case when month>='04' and month<='06' then money else 0 end) 第二季度, 

sum( case when month>='07' and month<='09' then money else 0 end) 第三季度, 

sum( case when month>='10' and month<='12' then money else 0 end) 第四季度 

from T_ACCOUNT where year='2012' group by areaid 

七、分析函数

以下三个分析函数可以用于排名使用。

下图为三种排名方式的举例

image-20210116213338630

(1) RANK 相同的值排名相同,排名跳跃

需求:对 T_ACCOUNT 表的 usenum 字段进行排序,相同的值排名相同,排名跳跃

语句:

select rank() over(order by usenum desc ),usenum from T_ACCOUNT 

(2) DENSE_RANK 相同的值排名相同,排名连续

需求:对 T_ACCOUNT 表的 usenum 字段进行排序,相同的值排名相同,排名连续

语句:

select dense_rank() over(order by usenum desc ),usenum from T_ACCOUNT 

(3) ROW_NUMBER 返回连续的排名,无论值是否相等

需求:对 T_ACCOUNT 表的 usenum 字段进行排序,返回连续的排名,无论值是否相等

语句:

select row_number() over(order by usenum desc ),usenum from T_ACCOUNT  

用 row_number()分析函数实现的分页查询相对三层嵌套子查询要简单的多:

select * from 

(select row_number() over(order by usenum desc ) 

rownumber,usenum from T_ACCOUNT) 

where rownumber>10 and rownumber<=20 

八、集合运算

(一)什么是集合运算

集合运算,集合运算就是将两个或者多个结果集组合成为一个结果集。集合运算 包括:

··UNION ALL(并集),返回各个查询的所有记录,包括重复记录。

··UNION(并集),返回各个查询的所有记录,不包括重复记录。

··INTERSECT(交集),返回两个查询共有的记录。

··MINUS(差集),返回第一个查询检索出的记录减去第二个查询检索出的记录之 后剩余的记录。

(二)并集运算

UNION ALL 不去掉重复记录

select * from t_owners where id<=7 union all select * from t_owners where id>=5 

UNION 去掉重复记录

select * from t_owners where id<=7 union select * from t_owners where id>=5  

(三)交集运算

select * from t_owners where id<=7 intersect select * from t_owners where id>=5 

(四)差集运算

select * from t_owners where id<=7  minus select * from t_owners where id>=5 

如果我们用 minus 运算符来实现分页,语句如下:

select rownum,t.* from T_ACCOUNT t where rownum<=20 minus select rownum,t.* from T_ACCOUNT t where rownum<=10 

作者:耿鬼不会笑
时间:2021年1月
  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值