Oracle语句练习

1. 查询

(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;

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;
--(四)基于伪列的查询--伪列只能查询,不能进行增删改操作
--1.ROWID
select rowID,t.* from T_AREA t;
--指定ROWID来查询记录
select rowID,t.* from T_AREA t where ROWID='AAGBTWAAKAAKqx9AAA';
--2.ROWNUM和rowid
select rownum,rowid,id,name from T_OWNERTYPE;

--(五)聚合统计
--1. 聚合函数
--求和 sum 需求:统计 2012 年所有用户的用水量总和
select sum(usenum) from t_account where year='2012';
--求平均 avg 统计 2012 年所有用水量(字数)的平均值
select avg(usenum) from T_ACCOUNT where year='2012';
--求最大值 max
select max(usenum) from T_ACCOUNT where year='2012';
--求最小值 min
select min(usenum) from T_ACCOUNT where year='2012';
--统计记录个数 count
select count(*) from T_OWNERS t where ownertypeid=1;
--分组聚合 Group by
select areaid,sum(money) from t_account group by areaid;
--分组后条件查询 having 查询水费合计大于 16900 的区域及水费合计
select areaid,sum(money) from t_account group by areaid 
having sum(money)>169000;

--二、连接查询
--(一)多表内连接查询
--需求:查询显示业主编号,业主名称,业主类型名称
select o.id 业主编号,o.name 业主名称,ot.name 业主类型 
from T_OWNERS o,T_OWNERTYPE ot 
where o.ownertypeid=ot.id;
--需求:查询显示业主编号,业主名称、地址和业主类型
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;
--需求:查询显示业主编号、业主名称、地址、所属区域、业主分类
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;

--(二)左外连接查询 --得截图
--需求:查询业主的账务记录,显示业主编号、名称、年、月、金额。如果此业主 没有账务记录也要列出姓名
SELECT T_OWNERS.id,T_OWNERS.name,T_ACCOUNT.year,T_ACCOUNT.month,T_ACCOUNT.money 
FROM T_OWNERS left join T_ACCOUNT 
on T_OWNERS.id=T_ACCOUNT.owneruuid;
--连表查询
SELECT T_OWNERS.id,T_OWNERS.name,T_ACCOUNT.year,T_ACCOUNT.month,T_ACCOUNT.money 
FROM T_OWNERS ,T_ACCOUNT 
where T_OWNERS.id=T_ACCOUNT.owneruuid;

--三、子查询
--(一)where 子句中的子查询
-- 单行子查询 需求:查询 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  any all
--需求:查询地址编号为 1 、3、4 的业主记录
select * from T_OWNERS where addressid in ( 1,3,4);
--需求:查询地址含有“花园”的业主的信息
select * from T_OWNERS where addressid in 
(select id from t_address where name like '%花园%');

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

--(二)from 子句中的子查询
select * from(select o.id 业主编号,o.name 业主名称,ot.name 业主类型 
from T_OWNERS o,T_OWNERTYPE ot where o.ownertypeid=ot.id) where 业主类型='居民';

--(三)select 子句中的子查询
--需求:列出业主信息,包括 ID,名称,所属地址.
select id,name,(select name from t_address where id=addressid) addressname from t_owners;
--需求:列出业主信息,包括 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;

--四、分页查询
--(一)简单分页
select rownum r,t.* from T_ACCOUNT t where rownum<=10;
--查询结果为null因为 rownum 是在查询语句扫描每条记录时产生的,所以不能使用“大于” 符号,
--只能使用“小于”或“小于等于” ,只用“等于”也不行。
select rownum,t.* from T_ACCOUNT t where rownum>10 and rownum<=20;
--子查询来实现
select * from (select rownum r,t.* from T_ACCOUNT t where rownum<=20) where r>10;

--(二)基于排序的分页
select * from(
select rownum r,t.* from T_ACCOUNT t 
where rownum<=20 order by usenum desc) 
where r>10;

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

--五、单行函数
--求字符串长度 LENGTH
select length('ABCD') from dual;
--求字符串的子串 SUBSTR
select substr('ABCD',2,2) from dual;
--字符串拼接 CONCAT
select concat('ABC','D') from dual;
--使用||拼接
select 'ABC'||'D' from dual;

--(二)数值函数
select round(100.567) from dual;
--四舍五入保留而二位
select round(100.567,2) from dual;
--截取函数 TRUNC
select trunc(100.567) from dual;--100
select trunc(100.567,2) from dual;--100.56
--取模 MOD
select mod(10,3) from dual;
--(三)日期函数
select sysdate from dual;
--加月函数 ADD_MONTHS :在当前日期基础上加指定的月
select add_months(sysdate,2) from dual;
--求所在月最后一天 LAST_DAY
select last_day(sysdate) from dual;


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

--TO_NUMBER
select to_number('100') from dual;

--(五)其它函数
--空值处理函数 NVL
select NVL(NULL,0) from dual;
--NVL2(检测的值,如果不为 null 的值,如果为 null 的值)
select PRICE,MINNUM,NVL2(MAXNUM,to_char(MAXNUM) , '不限') 
from T_PRICETABLE where OWNERTYPEID=1;

--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;

--六、集合运算
--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;
--INTERSECT(交集),返回两个查询共有的记录
select * from t_owners where id<=7 
intersect 
select * from t_owners where id>=5;
--MINUS(差集),返回第一个查询检索出的记录减去第二个查询检索出的记录之 后剩余的记录
select * from t_owners where id<=7
minus 
select * from t_owners where id>=5;

(1.2).视图 ,序列,同义词,索引

--视图视图是一种数据库对象,是从一个或者多个数据表或视图中导出的虚表,视
--图所对应的数据并不真正地存储在视图中,而是存储在所引用的数据表中,视图
--的结构和数据是对数据表进行查询的结果。
--根据创建视图时给定的条件,视图可以是一个数据表的一部分,也可以是多
--个基表的联合,它存储了要执行检索的查询语句的定义,以便在引用该视图时使用
--简单视图的创建与使用
create or replace view view_owners1 as
select * from T_OWNERS where ownertypeid=1;
--创建只读视图
create or replace view view_owners2 as
select * from T_OWNERS where ownertypeid=1 
with read only;
--利用该视图进行查询
select * from view_owners1 where addressid=1;
--对视图进行修改
update view_owners2 set name='王美人' where id=2;
--删除视图
DROP VIEW view_owners1;



--序列
--创建一个序列,开始值为11
create sequence seq_owners1 start with 11;
--删除序列
drop sequence seq_owners1;



--同义词
--同义词实质上是指定方案对象的一个别名。
--私有同义词【只允许特定的用户进行访问】
create synonym OWNERS for T_OWNERS;
--删除同义词
drop synonym OWNERS;
--根据同义词查询
select * from OWNERS;
--公有同义词【数据库的所有用户都能访问】
create public synonym OWNERS2 for T_OWNERS;
--根据公有同义词进行查询
select * from OWNERS2;



--索引【索引是用于加速数据存取的数据对象】
--需求:我们经常要根据业主名称搜索业主信息,所以我们基于业主表的 name 字段来建立索引。
create index index_owners_name on T_OWNERS(name);
--此时根据name查询记录,如果数据量达,将会快很多
select * from T_OWNERS where name = '刘华';


--唯一索引【如果我们需要在某个表某个列创建索引,而这列的值是不会重复的。这是我们可以创建唯一索引】
--需求:在业主表的水表编号一列创建唯一索引
create unique index index_owners_watermeter on
T_OWNERS(watermeter);

--复合索引【我们经常要对某几列进行查询,比如,我们经常要根据学历和性别对学员进行搜索,
--如果我们对这两列建立两个索引,因为要查两棵树,查询性能不一定高。那如何建立索引呢?】
--需求:根据地址和门牌号对学员表创建索引
create index owners_index_ah on T_OWNERS(addressid,housenumber);
--建立索引后,如果数据量大,会快很多
select * from t_owners where addressid='1' and housenumber = '1-1';

2. PL/SQL

(2.1)什么是 PL/SQL

PL/SQL(Procedure Language/SQL)是 Oracle 对 sql 语言的过程化扩展,指在 SQL 命令语言中增加了过程处理语句(如分支、循环等),使 SQL 语言具有过程处理能力。把 SQL 语言的数据操纵能力与过程语言的数据处理能力结合起来,使得 PLSQL 面向过程但比过程语言简单、高效、灵活和实用。

[declare 
 --声明变量
 ]
begin
 --代码逻辑 
[exception
 --异常处理
 ]
end;

(2.2)变量

需求:声明变量水费单价、水费字数、吨数、金额。对水费单价、字数、进行赋值 。吨数根据水费字数换算,规则为水费字数除以1000,并且四舍五入,保留两位小数。计算金额,金额=单价*吨数。输出单价 、数量和金额.

declare 
  v_price number(10,2);--单价
  v_usenum number;--水费字数
  v_usenum2 number(10,2);--吨数
  v_money number(10,2);--金额
begin 
 v_price:=2.45;--单价赋值
 v_usenum:=9213;--水费字数
 v_usenum2:=round(v_usenum/1000,2);--吨数
 v_money:=v_price*v_usenum2;--金额
 DBMS_OUTPUT.put_line('金额:'||v_money);
 end;




 --select 列名 into 变量名
 declare 
  v_price number(10,2);--单价
  v_usenum number;--水费字数
  v_usenum2 number(10,2);--吨数
  v_money number(10,2);--金额
  v_num0 number;--上月水表数
  v_num1 number;--本月水表数
begin 
 v_price:=2.45;--单价赋值
--从数据库查询
select usenum into v_usenum from t_account
where year = '2012' and month = '01' and owneruuid=1;
 v_usenum2:=round(v_usenum/1000,2);--吨数
 v_money:=v_price*v_usenum2;--金额
 DBMS_OUTPUT.put_line('字数:'||v_usenum||' 金额:'||v_money);
 end;

(2.3)属性类型

%TYPE 引用型        作用:引用某表某列的字段类型


----属性类型(引用型 表名 列名%type)
declare 
  v_price number(10,2);--单价
  v_usenum t_account.usenum%type;--水费字数
  v_usenum2 number(10,2);--吨数
  v_money number(10,2);--金额
  v_num0 t_account.num0%type;--上月水表数
  v_num1 t_account.num1%type;--本月水表数
begin 
 v_price:=2.45;--单价赋值
--从数据库查询并赋值
select usenum,num0,num1 into v_usenum,v_num0,v_num1 from t_account
where year = '2012' and month = '01' and owneruuid=1;
 v_usenum2:=round(v_usenum/1000,2);--吨数
 v_money:=v_price*v_usenum2;--金额
 DBMS_OUTPUT.put_line('字数:'||v_usenum||' 金额:'||v_money||' v_num0:'||v_num0|| ' v_num1:'||v_num1);
 end;



----%ROWTYPE 记录型 ,上例中的例子可以用下面的代码代替
----标识某个表的行记录类型
 ----属性类型(引用型 表名%rowtype)
declare 
  v_price number(10,2);--单价
  v_usenum2 number(10,2);--吨数
  v_money number(10,2);--金额
  v_account t_account%rowtype;--台账行记录类型
begin 
 v_price:=2.45;--单价赋值
--从数据库查询并赋值
select * into v_account from t_account
where year = '2012' and month = '01' and owneruuid=1;
 v_usenum2:=round(v_account.usenum/1000,2);--吨数
 v_money:=v_price*v_usenum2;--金额
 DBMS_OUTPUT.put_line('字数:'||v_account.usenum||' 金额:'||v_money);
 exception 
   when no_data_found then 
   DBMS_OUTPUT.put_line('没有找到账务数据');
 end;

(2.4)异常

image.png
--异常1
declare 
  v_price number(10,2);--单价
  v_usenum2 number(10,2);--吨数
  v_money number(10,2);--金额
  v_account t_account%rowtype;--台账行记录类型
begin 
 v_price:=2.45;--单价赋值
--从数据库查询并赋值
select * into v_account from t_account
where year = '2012' and month = '01' and owneruuid=200;
 v_usenum2:=round(v_account.usenum/1000,2);--吨数
 v_money:=v_price*v_usenum2;--金额
 DBMS_OUTPUT.put_line('字数:'||v_account.usenum||' 金额:'||v_money);
 exception 
   when no_data_found then 
   DBMS_OUTPUT.put_line('没有找到账务数据');
   when TOO_MANY_ROWS then 
   DBMS_OUTPUT.put_line('返回多行账务');
 end;
-----异常返回:没有找到账务数据

 
--异常2
declare 
  v_price number(10,2);--单价
  v_usenum2 number(10,2);--吨数
  v_money number(10,2);--金额
  v_account t_account%rowtype;--台账行记录类型
begin 
 v_price:=2.45;--单价赋值
--从数据库查询并赋值
select * into v_account from t_account
where year = '2012' and month = '01';
v_usenum2:=round(v_account.usenum/1000,2);--吨数
v_money:=v_price*v_usenum2;--金额
DBMS_OUTPUT.put_line('字数:'||v_account.usenum||' 金额:'||v_money);
exception 
when no_data_found then 
DBMS_OUTPUT.put_line('没有找到账务数据');
when TOO_MANY_ROWS then 
DBMS_OUTPUT.put_line('返回多行账务数据');
end;

-----异常返回:返回多行账务数据

(2.5)条件判断

--elsif 逻辑判断
 declare
 v_price1 number(10,2);--不足 5 吨的单价
 v_price2 number(10,2);--超过 5 吨不足 10 吨单价
 v_price3 number(10,2); --超过 10 吨单价
 v_account T_ACCOUNT%ROWTYPE;--记录型
 v_usenum2 number(10,2);--使用吨数
 v_money number(10,2);--水费金额
begin
--对单价进行赋值
 v_price1:=2.45;
 v_price2:=3.45;
 v_price3:=4.45;
--赋值
select * into v_account from T_ACCOUNT 
where year='2012' and month='01' and owneruuid=1;
--使用吨数
v_usenum2:= round(v_account.usenum/1000,2);
--计算金额(阶梯水费)
if v_usenum2<=5 then--第一个阶梯
v_money:=v_price1*v_usenum2;
elsif v_usenum2>5 and v_usenum2<=10 then --第二个阶梯
v_money:=v_price1*5 + v_price2*( v_usenum2-5); 
else --第三个阶梯
v_money:=v_price1*5 +v_price2*5 + v_price3*( v_usenum2-10 );
end if;
DBMS_OUTPUT.put_line('吨数: '||v_usenum2||' 金额: '||v_money||' 上月字数: '||v_account.num0||' 本月字数:'||v_account.num1);
exception
when NO_DATA_FOUND then
DBMS_OUTPUT.put_line('没有找到数据');
when TOO_MANY_ROWS then
DBMS_OUTPUT.put_line('返回的数据有多行');
end;

(2.6)循环

--循环
declare
  v_num number:=1;
begin 
  loop
  dbms_output.put_line(v_num);
  v_num:=v_num+1;
  exit when v_num>100;
  end loop; 
end ;

--有条件循环
declare
v_num number:=1;
begin
 while v_num<=100
 loop
 dbms_output.put_line(v_num);
 v_num:=v_num+1; 
 end loop; 
end ;

--for循环
begin
 for v_num in 1 .. 100
 loop
  dbms_output.put_line(v_num); 
 end loop;
end;

(2.7)游标

游标是系统为用户开设的一个数据缓冲区,存放 SQL 语句的执行结果。我们可以把游标理解为 PL/SQL 中的结果集。


image.png
--游标
declare
 v_pricetable T_PRICETABLE%rowtype;--价格行对象
 cursor cur_pricetable is select * from T_PRICETABLE where ownertypeid=1;--定义游标
begin
 open cur_pricetable;--打开游标
 loop
 fetch cur_pricetable into v_pricetable;--提取游标到变量
 exit when cur_pricetable%notfound;--当游标到最后一行下面退出循环
 dbms_output.put_line( '价格:'||v_pricetable.price ||'吨位:'||v_pricetable.minnum||'-'||v_pricetable.maxnum ); 
 end loop; 
 close cur_pricetable;--关闭游标
end ;

--带参数的游标
declare
 v_pricetable T_PRICETABLE%rowtype;--价格行对象
 cursor cur_pricetable(v_ownertype number) is select * from T_PRICETABLE where ownertypeid=v_ownertype;--定义游标
begin
 open cur_pricetable(1);--打开游标
 loop
 fetch cur_pricetable into v_pricetable;--提取游标到变量
 exit when cur_pricetable%notfound;--当游标到最后一行下面退出循环
 dbms_output.put_line( '价格:'||v_pricetable.price ||'吨位:'||v_pricetable.minnum||'-'||v_pricetable.maxnum); 
 end loop; 
 close cur_pricetable;--关闭游标
end ;


--for循环带参数的游标
declare
 --v_pricetable T_PRICETABLE%rowtype;--价格行对象
 cursor cur_pricetable(v_ownertype number) is select * from T_PRICETABLE where ownertypeid=v_ownertype;--定义游标
begin
 for  v_pricetable in cur_pricetable(1) --自动打开关闭
 loop
 dbms_output.put_line( '价格:'||v_pricetable.price ||'吨位:'||v_pricetable.minnum||'-'||v_pricetable.maxnum); 
 end loop; 
end ;

3.存储函数

CREATE [ OR REPLACE ] FUNCTION 函数名称
(参数名称 参数类型, 参数名称 参数类型, ...)
RETURN 结果变量数据类型
IS
变量声明部分;
BEGIN
逻辑部分;
RETURN 结果变量;
[EXCEPTION
异常处理部分]
END;

--自定义存储函数--需求: 创建存储函数,根据地址 ID 查询地址名称
create or replace function fn_getaddress
(v_id number)
return varchar2
is 
  v_name varchar2(30);
begin 
    --查询地址表
   select name into v_name from t_address where id=v_id;
   return v_name;
end;
--测试此函数:
select fn_getaddress(2) from dual;

--需求:查询业主 ID,业主名称,业主地址,业主地址使用刚才我们创建的函数来实现。
select id 编号,name 业主名称,fn_getaddress(addressid) 地址 from t_owners;

4.存储过程

存储过程与存储函数都可以封装一定的业务逻辑并返回结果,存在区别如
下:
1、存储函数中有返回值,且必须返回;而存储过程没有返回值,可以通过
传出参数返回多个值。 2、存储函数可以在 select 语句中直接使用,而存储过程不能。过程多数是
被应用程序所调用。
3、存储函数一般都是封装一个查询结果,而存储过程一般都封装一段事务
代码


create sequence seq_owners start with 11;
--存储过程
create or replace procedure pro_owners_add
(
v_name varchar2,  --名称
v_addressid number,   --地址编号
v_housenumber varchar2, --门牌号
v_watermeter varchar2, --水表号
v_ownertypeid number --业主类型
)
is
begin 
  insert into t_owners 
      values(seq_owners.nextval,v_name,v_addressid,v_housenumber,v_watermeter, sysdate,v_ownertypeid);
  commit;
end;

--调用不带传出参数的存储过程.
call pro_owners_add('马大哈',2,'22333','66777',1);

--使用begin end 调用存储过程.
begin
   pro_owners_add('马小哈',2,'22333','66777',1);
end;

--带传出参数的存储过程
create or replace procedure pro_owners_add1
(
v_name varchar2,  --名称
v_addressid number,   --地址编号
v_housenumber varchar2, --门牌号
v_watermeter varchar2, --水表号
v_ownertypeid number ,--业主类型
v_id out number --
)
is
begin 
  --对传出参数赋值
  select seq_owners.nextval into v_id from dual;
  insert into t_owners 
      values(v_id,v_name,v_addressid,v_housenumber,v_watermeter, sysdate,v_ownertypeid);
  commit;
end;

--使用begin end 调用传出参数的存储过程
declare 
 v_id number;
begin 
  pro_owners_add1('马二哈',2,'22333','66777',1,v_id);
  dbms_output.put_line(v_id);
end;

5..触发器

触发器分类
前置触发器(BEFORE)
后置触发器(AFTER)
CREATE [or REPLACE] TRIGGER 触发器名
BEFORE | AFTER
[DELETE ][[or] INSERT] [[or]UPDATE [OF 列名]]
ON 表名
[FOR EACH ROW ][WHEN(条件) ]
declare
……
begin
PLSQL 块
End ;

--触发器【电视遥控开关】
--前置触发器,修改num1的值之后,usenum值自动修改了 --自动commit
create or replace trigger tri_account_num1
before 
update of num1
on t_account
for each row
declare
begin 
  --通过伪记录变量修改usenum字段的值
  :new.usenum:=:new.num1-:new.num0;
end;


--后置触发器 --自动commit
create table t_owners_log(
 updatetime date,
 ownerid number,
 oldname varchar2(30),
 newname varchar(30)
);
create or replace trigger tri_owners_log
after 
update of name
on t_owners
for each row
declare
begin
 insert into t_owners_log values(sysdate,:new.id,:old.name,:new.name);
end;

你可能感兴趣的:(Oracle语句练习)