(一)简单条件查询
需求:查询水表编号为 30408 的业主记录
查询语句:
select * from T_OWNERS where watermeter='30408'
需求:查询业主名称包含“刘”的业主记录
查询语句:
select * from t_owners where name like '%刘%'
需求:查询业主名称包含“刘”的并且门牌号包含 5 的业主记录
查询语句:
select * from t_owners where name like '%刘%' and housenumber like '%5%'
需求:查询业主名称包含“刘”的或者门牌号包含 5 的业主记录
查询语句:
select * from t_owners where name like '%刘%' or housenumber like '%5%'
需求:查询业主名称包含“刘”的或者门牌号包含 5 的业主记录,并且地址编号为 3 的记录。
语句:
select * from t_owners where (name like '%刘%' or housenumber like '%5%') and addressid=3
需求:查询台账记录中用水字数大于等于 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
我们可以通过指定 ROWID 来查询记录
select rowID,t.* from T_AREA t where ROWID='AAAM1uAAGAAAAD8AAC';
2 ROWNUM
在查询的结果集中,ROWNUM 为结果集中每一行标识一个行号,第一行返回 1,
第二行返回 2,以此类推。通过 ROWNUM 伪列可以限制查询结果集中返回的行数.
查询语句:
select rownum,t.* from T_OWNERTYPE t
ORACLE 的聚合统计是通过分组函数来实现的,与 MYSQL 一致。
(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
需求:按区域分组统计水费合计数
语句:
select areaid,sum(money) from t_account group by areaid
查询结果:
需求:查询水费合计大于 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
需求:查询业主的账务记录,显示业主编号、名称、年、月、金额。如果此业主没有账务记录也要列出姓名。
分析:我们要查询这个结果,需要用到 T_OWNERS(业主表) ,T_ACCOUNT(台账表) 按照查询结果,业主表为左表、账务表为右表。
按照 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(+)
如果是左外连接,就在右表所在的条件一端填上(+)
需求:查询业主的账务记录,显示业主编号、名称、年、月、金额。如果账务记
录没有对应的业主信息,也要列出记录。如下图:
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' ) ;
返回了多条记录
多行操作符
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 子句的子查询必须为单行子查询
select id,name, (select name from t_address where id=addressid) addressname from t_owners
语句:
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
需求:分页查询台账表 T_ACCOUNT,每页 10 条记录,按使用字数降序排序。
我们查询第 2 页数据,如果基于上边的语句添加排序,语句如下:
select * from
(select rownum r,t.* from T_ACCOUNT t where rownum<=20 order
by usenum desc)
where r>10
你会发现排序后的 R 是乱的。这是因为 ROWNUM 伪列的产生是在表记录扫描
是产生的,而排序是后进行的,排序时 R 已经产生了,所以排序后 R 是乱的。
那该如何写呢?
很简单,我们只要再嵌套一层循环(一共三层),让结果先排序,然后对排序后
的结果再产生 R,这样就不会乱了。
语句如下:
select * from
(select rownum r,t.* from
(select * from T_ACCOUNT order by usenum desc) t
where rownum<=20 )
where r>10
常用字符函数讲解:
(1)求字符串长度 LENGTH
语句:
select length('ABCD') from dual;
(2)求字符串的子串 SUBSTR
语句:
select substr('ABCD',2,2) from dual;
(3)字符串拼接 CONCAT
语句:
select concat('ABC','D') from dual;
(3)字符串拼接 CONCAT
语句:
select concat('ABC','D') from dual;
(二)数值函数
常用数值函数讲解:
(1)四舍五入函数 ROUND
语句:
select round(100.567) from dual;
语句: 跟参数 是保留两位小数的意思
select round(100.567,2) from dual;
(2)截取函数 TRUNC 不跟参数表示小数点后截取0位,跟参数代表多少位
语句:
select trunc(100.567) from dual ;
(3)取模 MOD (取余数的意思)
语句:
select mod(10,3) from dual;
(三)日期函数
我们用 sysdate 这个系统变量来获取当前日期和时间
语句如下:
select sysdate from dual;
常用日期函数讲解:
(1)加月函数 ADD_MONTHS :在当前日期基础上加指定的月(现在7月参数2 ,就是九月)
语句:
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;
常用转换函数讲解:
(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;
如果最大值是null的话,就显示9999999;
(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 (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;
以下三个分析函数可以用于排名使用。
下图为三种排名方式的举例
(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(差集),返回第一个查询检索出的记录减去第二个查询检索出的记录之
后剩余的记录。
UNIONALL 不去掉重复记录
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
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;