oracle(二)

自来水的建表语句


--建立价格区间表
create  table t_pricetable
(
id number primary key,
price number(10,2),
ownertypeid number,
minnum number,
maxnum number
);


--业主类型
create table t_ownertype
(
id number primary key,
name varchar2(30)
);

--业主表
create table t_owners
(
id number primary key,
name varchar2(30),
addressid number,
housenumber varchar2(30),
watermeter varchar2(30),
adddate date,
ownertypeid number
);



--区域表
create table t_area
(
id number,
name varchar2(30)
);

--收费员表
create table t_operator
(
id number,
name varchar2(30)
);


--地址表
create table t_address
(
id number primary key,
name varchar2(100),
areaid number,
operatorid number
);


--账务表--
create table t_account 
(
id number primary key,
owneruuid number,
ownertype number,
areaid number,
year char(4),
month char(2),
num0 number,
num1 number,
usenum number,
meteruser number,
meterdate date,
money number(10,2),
isfee char(1),
feedate date,
feeuser number
);


create sequence seq_account;

--业主类型
insert into t_ownertype values(1,'居民');
insert into t_ownertype values(2,'行政事业单位');
insert into t_ownertype values(3,'商业');

--地址信息--
insert into t_address values( 1,'明兴花园',1,1);
insert into t_address values( 2,'鑫源秋墅',1,1);
insert into t_address values( 3,'华龙苑南里小区',2,2);
insert into t_address values( 4,'河畔花园',2,2);
insert into t_address values( 5,'霍营',2,2);
insert into t_address values( 6,'回龙观东大街',3,2);
insert into t_address values( 7,'西二旗',3,2);

--业主信息
insert into t_owners values(1,'范冰',1,'1-1','30406',to_date('2015-04-12','yyyy-MM-dd'),1 );
insert into t_owners values(2,'王强',1,'1-2','30407',to_date('2015-02-14','yyyy-MM-dd'),1 );
insert into t_owners values(3,'马腾',1,'1-3','30408',to_date('2015-03-18','yyyy-MM-dd'),1 );
insert into t_owners values(4,'林小玲',2,'2-4','30409',to_date('2015-06-15','yyyy-MM-dd'),1 );
insert into t_owners values(5,'刘华',2,'2-5','30410',to_date('2013-09-11','yyyy-MM-dd'),1 );
insert into t_owners values(6,'刘东',2,'2-2','30411',to_date('2014-09-11','yyyy-MM-dd'),1 );
insert into t_owners values(7,'周健',3,'2-5','30433',to_date('2016-09-11','yyyy-MM-dd'),1 );
insert into t_owners values(8,'张哲',4,'2-2','30455',to_date('2016-09-11','yyyy-MM-dd'),1 );
insert into t_owners values(9,'昌平区中西医结合医院',5,'2-2','30422',to_date('2016-10-11','yyyy-MM-dd'),2 );
insert into t_owners values(10,'美廉美超市',5,'4-2','30423',to_date('2016-10-12','yyyy-MM-dd'),3 );


--操作员
insert into t_operator values(1,'马小云');
insert into t_operator values(2,'李翠花');



--地区--
insert into t_area values(1,'海淀');
insert into t_area values(2,'昌平');
insert into t_area values(3,'西城');
insert into t_area values(4,'东城');
insert into t_area values(5,'朝阳');
insert into t_area values(6,'玄武');


--价格表--

insert into t_pricetable values(1,2.45,1,0,5);
insert into t_pricetable values(2,3.45,1,5,10);
insert into t_pricetable values(3,4.45,1,10,null);

insert into t_pricetable values(4,3.87,2,0,5);
insert into t_pricetable values(5,4.87,2,5,10);
insert into t_pricetable values(6,5.87,2,10,null);

insert into t_pricetable values(7,4.36,3,0,5);
insert into t_pricetable values(8,5.36,3,5,10);
insert into t_pricetable values(9,6.36,3,10,null);

--账务表--
insert into t_account values( seq_account.nextval,1,1,1,'2012','01',30203,50123,0,1,sysdate,34.51,'1',to_date('2012-02-14','yyyy-MM-dd'),2 );
insert into t_account values( seq_account.nextval,1,1,1,'2012','02',50123,60303,0,1,sysdate,23.43,'1',to_date('2012-03-14','yyyy-MM-dd'),2 );
insert into t_account values( seq_account.nextval,1,1,1,'2012','03',60303,74111,0,1,sysdate,45.34,'1',to_date('2012-04-14','yyyy-MM-dd'),2 );
insert into t_account values( seq_account.nextval,1,1,1,'2012','04',74111,77012,0,1,sysdate,52.54,'1',to_date('2012-05-14','yyyy-MM-dd'),2 );
insert into t_account values( seq_account.nextval,1,1,1,'2012','05',77012,79031,0,1,sysdate,54.66,'1',to_date('2012-06-14','yyyy-MM-dd'),2 );
insert into t_account values( seq_account.nextval,1,1,1,'2012','06',79031,80201,0,1,sysdate,76.45,'1',to_date('2012-07-14','yyyy-MM-dd'),2 );
insert into t_account values( seq_account.nextval,1,1,1,'2012','07',80201,88331,0,1,sysdate,65.65,'1',to_date('2012-08-14','yyyy-MM-dd'),2 );
insert into t_account values( seq_account.nextval,1,1,1,'2012','08',88331,89123,0,1,sysdate,55.67,'1',to_date('2012-09-14','yyyy-MM-dd'),2 );
insert into t_account values( seq_account.nextval,1,1,1,'2012','09',89123,90122,0,1,sysdate,112.54,'1',to_date('2012-10-14','yyyy-MM-dd'),2 );
insert into t_account values( seq_account.nextval,1,1,1,'2012','10',90122,93911,0,1,sysdate,76.21,'1',to_date('2012-11-14','yyyy-MM-dd'),2 );
insert into t_account values( seq_account.nextval,1,1,1,'2012','11',93911,95012,0,1,sysdate,76.25,'1',to_date('2012-12-14','yyyy-MM-dd'),2 );
insert into t_account values( seq_account.nextval,1,1,1,'2012','12',95012,99081,0,1,sysdate,44.51,'1',to_date('2013-01-14','yyyy-MM-dd'),2 );

insert into t_account values( seq_account.nextval,2,1,3,'2012','01',30334,50433,0,1,sysdate,34.51,'1',to_date('2013-02-14','yyyy-MM-dd'),2 );
insert into t_account values( seq_account.nextval,2,1,3,'2012','02',50433,60765,0,1,sysdate,23.43,'1',to_date('2013-03-14','yyyy-MM-dd'),2 );
insert into t_account values( seq_account.nextval,2,1,3,'2012','03',60765,74155,0,1,sysdate,45.34,'1',to_date('2013-04-14','yyyy-MM-dd'),2 );
insert into t_account values( seq_account.nextval,2,1,3,'2012','04',74155,77099,0,1,sysdate,52.54,'1',to_date('2013-05-14','yyyy-MM-dd'),2 );
insert into t_account values( seq_account.nextval,2,1,3,'2012','05',77099,79076,0,1,sysdate,54.66,'1',to_date('2013-06-14','yyyy-MM-dd'),2 );
insert into t_account values( seq_account.nextval,2,1,3,'2012','06',79076,80287,0,1,sysdate,76.45,'1',to_date('2013-07-14','yyyy-MM-dd'),2 );
insert into t_account values( seq_account.nextval,2,1,3,'2012','07',80287,88432,0,1,sysdate,65.65,'1',to_date('2013-08-14','yyyy-MM-dd'),2 );
insert into t_account values( seq_account.nextval,2,1,3,'2012','08',88432,89765,0,1,sysdate,55.67,'1',to_date('2013-09-14','yyyy-MM-dd'),2 );
insert into t_account values( seq_account.nextval,2,1,3,'2012','09',89765,90567,0,1,sysdate,112.54,'1',to_date('2013-10-14','yyyy-MM-dd'),2 );
insert into t_account values( seq_account.nextval,2,1,3,'2012','10',90567,93932,0,1,sysdate,76.21,'1',to_date('2013-11-14','yyyy-MM-dd'),2 );
insert into t_account values( seq_account.nextval,2,1,3,'2012','11',93932,95076,0,1,sysdate,76.25,'1',to_date('2013-12-14','yyyy-MM-dd'),2 );
insert into t_account values( seq_account.nextval,2,1,3,'2012','12',95076,99324,0,1,sysdate,44.51,'1',to_date('2014-01-14','yyyy-MM-dd'),2 );

insert into t_account values( seq_account.nextval,100,1,3,'2012','12',95076,99324,0,1,sysdate,44.51,'1',to_date('2014-01-01','yyyy-MM-dd'),2 );
insert into t_account values( seq_account.nextval,101,1,3,'2012','12',95076,99324,0,1,sysdate,44.51,'1',to_date('2015-01-01','yyyy-MM-dd'),2 );

update t_account set usenum=num1-num0;
update t_account set money=usenum*2.45;
commit;

一、单表查询

1.1简单条件查询

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

查询结果:

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

查询结果:

1.2去掉重复记录

需求:查询业主表中的地址 ID, 不重复显示
语句:
select distinct addressid from T_OWNERS

查询结果:

 

1.3排序查询

1.升序排序--默认

需求:对 T_ACCOUNT 表按使用量进行升序排序
语句:
select * from T_ACCOUNT order by usenum
查询结果:

2.降序排序

需求:对 T_ACCOUNT 表按使用量进行降序排序
语句:
select * from T_ACCOUNT order by usenum desc

查询结果:

1.4基于伪列的查询

伪列:假的列。它是每一个行数据的物理地址。它的地址返回的就是一长串。你用oracle你可以不用建主键,主键的作用就是唯一标识,oracle的rowid相当于唯一标识。

rowid的查询效率比主键查询效率高???

rowid本身是物理地址,所谓物理地址他就是可以直接定位,主键查询的实质就是通过索引查询rowid,它要经过查找的过程才能找到他。所以rowid比主键查询更快

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是每一行的行号。他就是一个序号,他就是结果集的序号,他就会给结果集自动添加序号。

在查询的结果集中,ROWNUM 为结果集中每一行标识一个行号,第一行返回 1
第二行返回 2 ,以此类推。通过 ROWNUM 伪列可以限制查询结果集中返回的行数。
查询语句:
select rownum,t.* from T_OWNERTYPE t

查询结果:

我们的分页查询需要用到此伪列,

1.5聚合统计

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后一定是分组聚合的条件或者是聚合函数

需求:按区域分组统计水费合计数
语句:
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

查询结果:

二、连接查询

2.1多表内连接查询

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 业主类型

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

2.2左外连接查询--2种写法

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

分析:我们要查询这个结果,需要用到 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(+)

如果是左外连接,就在右表所在的条件一端填上(+),这是oracle特有的语法。
加号是oracle外链接的特殊语法记住就行了。

2.3右外连接查询

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

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

三、子查询

3.1where 子句中的子查询--2种

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. 多行子查询

  •  返回了多条记录
  • 多行操作符

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 '%花园%' )

查询结果:

3.2from 子句中的子查询---多行子查询

from 子句的子查询为多行子查询。
from后面接的是查询结果,原来from后面接的是表,可以吧from后面的查询结果看成一张表即可。
需求:查询显示业主编号,业主名称,业主类型名称,条件为业主类型为 居民
使用子查询实现。
语句:
select * from
(select o.id 业主编号,o.name 业主名称,ot.name 业主类型 
from T_OWNERS o,T_OWNERTYPE ot where o.ownertypeid=ot.id)
 where 业主类型='居民'

查询结果:

3.3select 子句中的子查询--单行字查询

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;

查询结果:

四、分页查询

4.1简单分页---2层嵌套

需求:分页查询台账表 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 是在查询语句扫描每条记录时产生的,所以不能使用“大于”
符号,只能使用“小于”或“小于等于” ,只用“等于”也不行。
注意:
rownum后面只能是小于或者小于等于,不能是大于或者大于等于或者等于都不行。
那怎么办呢?我们可以使用子查询来实现
select * from 
(select rownum r,t.* from T_ACCOUNT t where rownum<=20) 
where r>10

我们可以用rownum先产生值,然后再去做筛选。就是做一个子查询的结果。

查询结果:

4.2基于排序的分页---3层嵌套

需求:分页查询台账表 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 ,这样就不会乱了。
注意:分页查询是三层嵌套,不分页的就是二层嵌套。如果排序的话,先去排序,然后产生rownum,然后在一层嵌套。
语句如下:
select * from 
(select rownum r,t.* from 
(select * from T_ACCOUNT order by usenum desc) t
 where rownum<=20 )
 where r>10

结果如下:

五、单行函数--5种

函数就是你给他一个值,他返回一个值。单行函数就是你给他一个值,它经过运算之后,他在返回给你一个值。聚合函数/分组函数它是统计的是一列信息,最后给你一个汇总的数。

5.1字符函数

常用字符函数讲解:
1 )求字符串长度 LENGTH
伪表dual,他没有真实的意义,他的存在就是用来测试函数的。
语句:
select length('ABCD') from dual;

显示结果为:

(2 )求字符串的子串 SUBSTR
语句:
select substr('ABCD',2,2) from dual;

显示结果为:

3 )字符串拼接 CONCAT
语句:
select concat('ABC','D') from dual;

显示结果为:

我们也可以用 || 对字符串进行拼接---java中的|| 表示或,这里表示拼接
select 'ABC'||'D' from dual;
查询结果同上。

5.2数值函数

常用数值函数讲解:
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

查询结果如下:

5.3日期函数

我们用 sysdate 这个系统变量来获取当前日期和时间
语句如下:
select sysdate from dual

查询结果如下:

常用日期函数讲解:
1 )加月函数 ADD_MONTHS :在当前日期基础上加指定的月
语句:
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

查询结果如下:

其他的:

5.4转换函数

常用转换函数讲解:
1 )数字转字符串 TO_CHAR
语句:
select TO_CHAR(1024) from dual

查询结果:
靠右显示的数字,靠左显示的是字符串。

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

查询结果:

(2) 日期转字符串 TO_CHAR
语句:
select TO_DATE('2017-01-01','yyyy-mm-dd') 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

查询结果:

靠右显示的数字,靠左显示的是字符串。

5.5其它函数

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 )
rom T_OWNERS

六、行列转换

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

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

查询结果:

七、分析函数---3种

以下三个分析函数可以用于排名使用。
下图为三种排名方式的举例

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()分析函数实现的分页查询相对三层嵌套子查询要简单的多:--这里用2层,首先用row_number()进行排序,然后再用别名
select * from
 (select row_number() over(order by usenum desc ) rownumber,usenum from T_ACCOUNT)
 where rownumber>10

结果:

八、集合运算

8.1什么是集合运算

集合运算,集合运算就是将两个或者多个结果集组合成为一个结果集。集合运算
包括:
··UNION ALL( 并集 ) ,返回各个查询的所有记录,包括重复记录。
··UNION( 并集 ) ,返回各个查询的所有记录,不包括重复记录。
··INTERSECT( 交集 ) ,返回两个查询共有的记录。
··MINUS( 差集 ) ,返回第一个查询检索出的记录减去第二个查询检索出的记录之
后剩余的记录。

8.2并集运算

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

结果:

8.3交集运算

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

结果:

8.4差集运算

差集就是减法,就是吧第一个结果中出现的第二个结果的数据减出去。

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

结果:

九、综合案例

为《自来水收费系统》开发统计模块相关的功能

1.收费日报单(总)

统计某日的收费,按区域分组汇总,效果如下:

语句:

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

sum(usenum)/1000 "用水量(吨)" ,sum(money) 金额

from T_ACCOUNT

where to_char(feedate,'yyyy-mm-dd')='2012-05-14'

group by areaid

2.收费日报单(收费员)

统计某收费员某日的收费,按区域分组汇总,效果如下:

语句:

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

sum(usenum)/1000 "用水量(吨)" ,sum(money) 金额

from T_ACCOUNT

where to_char(feedate,'yyyy-mm-dd')='2012-05-14' 

and feeuser=2

group by areaid

3.收费月报表(总)

统计某年某月的收费记录,按区域分组汇总

语句:

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

sum(usenum)/1000 "用水量(吨)" ,sum(money) 金额

from T_ACCOUNT

where to_char(feedate,'yyyy-mm')='2012-05'

group by areaid

4.收费月报表(收费员)

统计某收费员某年某月的收费记录,按区域分组汇总

语句:

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

sum(usenum)/1000 "用水量(吨)" ,sum(money) 金额

from T_ACCOUNT

where to_char(feedate,'yyyy-mm')='2012-05' and feeuser=2

group by areaid

5.收费年报表(分区域统计)

统计某年收费情况,按区域分组汇总,效果如下:

语句:

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

sum(usenum)/1000 "用水量(吨)" ,sum(money) 金额

from T_ACCOUNT

where to_char(feedate,'yyyy')='2012' 

group by areaid

6.收费年报表(分月份统计)

统计某年收费情况,按月份分组汇总,效果如下

语句:

select to_char(feedate,'mm') 月份,sum(usenum)/1000 使用吨数,sum(money) 金额

from T_ACCOUNT

where  to_char(feedate,'yyyy')='2013'

GROUP BY to_char(feedate,'mm')

ORDER BY to_char(feedate,'mm')

7.收费年报表(分月份统计)

统计某年收费情况,按月份分组汇总,效果如下

语句:

select '用水量(吨)' 统计项,

      sum (case when to_char(feedate,'mm')='01'  then usenum else 0  end )/1000 一月,

      sum (case when to_char(feedate,'mm')='02'  then usenum else 0  end )/1000 二月,

      sum (case when to_char(feedate,'mm')='03'  then usenum else 0  end )/1000 三月,

      sum (case when to_char(feedate,'mm')='04'  then usenum else 0  end )/1000 四月,

      sum (case when to_char(feedate,'mm')='05'  then usenum else 0  end )/1000 五月,

      sum (case when to_char(feedate,'mm')='06'  then usenum else 0  end )/1000 六月,

      sum (case when to_char(feedate,'mm')='07'  then usenum else 0  end )/1000 七月,

      sum (case when to_char(feedate,'mm')='08'  then usenum else 0  end )/1000 八月,

      sum (case when to_char(feedate,'mm')='09'  then usenum else 0  end )/1000 九月,

      sum (case when to_char(feedate,'mm')='10'  then usenum else 0  end )/1000 十月,

      sum (case when to_char(feedate,'mm')='11'  then usenum else 0  end )/1000 十一月,

      sum (case when to_char(feedate,'mm')='12'  then usenum else 0  end )/1000 十二月

from T_ACCOUNT

where to_char(feedate,'yyyy')='2013'

UNION ALL

select '金额(元)' 统计项,

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

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

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

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

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

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

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

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

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

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

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

      sum (case when to_char(feedate,'mm')='12'  then money else 0  end ) 十二月

from T_ACCOUNT

where to_char(feedate,'yyyy')='2013'

8.统计用水量,收费金额(分类型统计)

根据业主类型分别统计每种居民的用水量(整数,四舍五入)及收费金额 ,如果该类型在台账表中无数据也需要列出值为0的记录 , 效果如下:

语句:

select ow.name,

 nvl( round(sum(usenum)/1000),0) "用水量(吨)" , nvl( sum(money),0) 金额

from T_OWNERTYPE ow ,T_ACCOUNT ac

where ow.id=ac.ownertype(+)  

group by ow.name

分析:这里所用到的知识点包括左外连接、sum()、分组group by 、round()  和nvl()

9.统计每个区域的业主户数,并列出合计

语句:

select ar.name 区域,count(ow.id) 业主户数

from T_AREA ar ,T_OWNERS ow,T_ADDRESS ad

where ad.id=ow.addressid and ad.areaid=ar.id

group by ar.name

union all

select '合计',count(1) from T_OWNERS 

  1. 统计每个区域的业主户数,如果该区域没有业主户数也要列出0

如图:

语句:

select ar.name 区域,count(owad.id) 业主户数

from T_AREA ar ,

(

select ow.id,ow.name,ad.areaid from T_OWNERS ow,T_ADDRESS ad where ow.addressid=ad.id

)

owad

where ar.id=owad.areaid(+)

group by ar.name

十、练习

1.表结构分析

1.请从表EMP中查找工种是职员CLERK或经理MANAGER的雇员姓名、工资。

select ename,sal from emp where job='CLERK' or job='MANAGER';

2.请在EMP表中查找部门号在10-30之间的雇员的姓名、部门号、工资、工作。

select ename,deptno,sal,job from emp where deptno between 10 and 30;

3.请从表EMP中查找姓名以J开头所有雇员的姓名、工资、职位。

select ename,sal,job from emp where ename like 'J%';

4.请从表EMP中查找工资低于2000的雇员的姓名、工作、工资,并按工资降序排列。

select ename,job,sal from emp where sal<=2000 order by sal desc;

5.请从表中查询工作是CLERK的所有人的姓名、工资、部门号、部门名称以及部门地址的信息。

select ename,sal,emp.deptno,dname,loc from emp,dept

where emp.deptno=dept.deptno and  job=’CLERK’;

6.在表EMP中查询所有工资高于JONES的所有雇员姓名、工作和工资。

select ename,job,sal from emp where sal>(select sal from emp where ename=’JONES’);

7.列出没有对应部门表信息的所有雇员的姓名、工作以及部门号。

select ename,job,deptno from emp where deptno not in (select deptno from dept);

8.查找工资在1000~3000之间的雇员所在部门的所有人员信息

select * from emp where deptno in (select distinct deptno from emp where sal between 1000 and 3000);

9.雇员中谁的工资最高。

select ename from emp where sal=(select max(sal) from emp);

select ename from (select * from emp order by sal desc) where rownum<=1;

10.查询所有雇员的姓名、SAL与COMM之和。

select ename,sal+nvl(comm,0) “sal-and-comm” from emp;

11.查询所有81年7月1日以前来的员工姓名、工资、所属部门的名字

select ename,sal,dname from emp,dept where emp.deptno=dept.deptno and hiredate<=to_date(‘1981-07-01’,’yyyy-mm-dd’);

12.查询各部门中81年1月1日以后来的员工数

select deptno,count(*) from emp where hiredate>=to_date(‘1981-01-01’,’yyyy-mm-dd’) group by deptno;

13.查询所有在CHICAGO工作的经理MANAGER和销售员SALESMAN的姓名、工资

select ename,sal from emp where (job=’MANAGER’ or job=’SALES’) and deptno in (select deptno from dept where loc=’CHICAGO’);

14.查询列出来公司就职时间超过24年的员工名单

select ename from emp where hiredate<=add_months(sysdate,-288);

15.查询于81年来公司所有员工的总收入(SAL和COMM)

select sum(sal+nvl(comm,0)) from emp where to_char(hiredate,’yyyy’)=1981’;

16.查询显示每个雇员加入公司的准确时间,按××××年××月××日 时分秒显示。

select ename,to_char(hiredate,'yyyy-mm-dd hh24:mi:ss') from emp;

17.查询公司中按年份月份统计各地的录用职工数量

select to_char(hiredate,'yyyy-mm'),loc,count(*) from emp,dept

   where emp.deptno=dept.deptno group by to_char(hiredate,'yyyy-mm'),loc;

18.查询列出各部门的部门名和部门经理名字

select dname,ename from emp,dept where emp.deptno=dept.deptno and job=’MANAGER’;

19.查询部门平均工资最高的部门名称和最低的部门名称

select dname from dept where deptno=(select deptno from (select deptno from emp group by deptno order by avg(sal) ) where rownum<=1)

    union all select dname from dept where deptno=(select deptno from (select deptno from emp group by deptno order by avg(sal) desc ) where rownum<=1);

20.查询与雇员号为7521员工的最接近的在其后进入公司的员工姓名及其所在部门名

select ename,dname

  from (select ename,deptno from 

    (select ename,deptno from emp where hiredate>(select hiredate from emp where empno=7521) order by hiredate ) where rownum<=1) e,dept

    where e.deptno=dept.deptno

  • 2
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值