结构化查询语言:Structured Query Language
数据的持久化(保存数据)
DDL 化表头
create table
(column name 列名)
(data type 数据类型 length 长度)
(constraint 约束 唯一且非空)
alter table 修改表结构
drop table
DML 填数据
insert 插入数据,一行
update 修改数据,某行的某列值/某些行的某列值/所有行的某列值
delete 删除一行
TCL --TransactionControl Langage
commit 提交
rollback 回滚(刚才作的动作消除了相当于ctrl+z)
DQL --Data QueryLangage
select 查询
DCL Data ControlLangage
grant 授权
revoke 收回授权
多用户系统
权限
例如:connect tarena/tarena
create table account();
grant select on account to jsd1303//给jsd1303看account表
revoke select on account to jsd1303//不给jsd1303看account表
connect jsd1303/jsd1303
select...from tarena.account
select...form account(jsd1303里的account)
create database 创建数据库
DBA(database adminstrator) 数据库管理(ocp)
在平台(os)安装oracle软件 unix,linux
linux:sql developer
solaris:192.168.0.20 192.168.0.23192.168.0.26 //数据库的IP
连接数据库需要的信息 数据库的IP 端口号 数据库名 用户名 口令
查询表:源表
desc account
select 语句的查询结果:结果集
投影操作:结果是部分列
选择操作:结果是部分行
连接操作:结果集来自多张表
select real_name,idcard_no fromaccount
selectbase_cost,base_duration,unit_cost from cost
select 语句包含多个子句
select 子句 实现投影操作
from 子句 标名
sql 4GL 我要什么,rdbms 解放程序员
列别名适合计算字段,原名和别名之间可以使用as关键字
别名中包含空格 特殊字符或者希望大小写敏感,用“”
双引号表示标识名,列别名就是一个标识名
oracle中的‘s用'''s'表示,其中的两个‘’表示中文‘
desc account;
selectnvl(base_cost,0)+(250-nvl(base_duration,0))*nvl(unit_cost,0) fee_250 from cost;
selectnvl(base_cost,0)+(250-nvl(base_duration,0))*nvl(unit_cost,0) "Fee 250"from cost;
select * from cost;
select real_name ||' '|| idcard_no client from account;
select real_name||'''s IDCARD NOis '||idcard_no||'.' carddd from account;
select distinct unix_host fromservice;
select子句后面可以跟列名,*,表达式(算术,字符串),distinct
distinct 对结果集去重
where 子句后跟条件表达式
列名 常量
比较运算符
文字值
子句后不能跟列别名
session 会话
select count(*) from v$session whereusername=‘JSD1303_1’;
会话(session)查看jsd1303_1进行登录的人数
课外练习:
1 有哪些不同包在线时常 base_duration
2 理解连接过程
3 预习where子句
比较:
select base_cost*12,base_duration*12 fromcost where base_cost*12=70.8;
select base_duration*12 from cost wherebase_cost=70.8/12;//这个相对来说较好
执行顺序:from-->where-->select
where 不可跟列别名,后尽量不跟表达式
“”引起来的oracle表示标识符
select unix_host from service where"OS_USERNAME"=“huangr“
select unix_host from service whereos_username=“huangr“;其中"huangr"表示列名
不加‘’也表示标识符select unix_host from service where os_username=huangr;其中huangr表示列名
select unix_host from service whereos_username=‘HUANGR’;//字符串不一样
upper(p1)大写 lower(p1)小写 initcap(p1)首字符大写
select unix_host from service whereupper(os_username) = 'HUANGR';
select unix_host from service wherelower(os_username) = 'huangr';
select unix_host from service whereinitcap(os_username) = 'Huangr';
where 条件用and or连接,并且and优先级高于or
between..A1..and..B1. ==[A1,B1]
多值运算的集合 in () =any()
select base_cost from cost where base_costin(5.9,8.5,10.5);
select base_cost , base_duration from costwhere base_cost = any(5.9,8.5,10.5);
in() 多值运算的集合
= 单值运算
=any() 多值运算的集合
null不等于0
null不等于空格
算术表达式中包含null结果为null
算术表达式中包含null需空值转换nvl
nvl()类型可以是number characterdate,参数类型必须一致
=精确比较
like 像....什么一样模糊匹配
%表示0个任意多个字符
_表示任意一个字符
通配符的转义: _的转义
select os_username,unix_host fromservice where os_username like 'h\_%' escape '\';
is null:
select base_cost,unit_cost from costwhere unit_cost is null;
不等于:<> ^= !=
is null -------------> isnot null
like--------------- >not like
between and ---------- > not between and
in-----------------> not in<============> <>and <>and<> <>all
select base_cost,unit_cost from costwhere base_cost <>5.9 and base_cost^=8.5 and base_cost!=10.5;
not in()集合中包含null值,select语句执行结果为no rows selected
select base_cost,unit_costfrom cost where base_cost not in(5.9,8.5,10.5) or base_cost is null;
in()集合中包含null值,select语句执行结果和没有null都是一样的
select base_cost,unit_cost from costwhere base_cost in (5.9,8.5,10.5) or base_cost is null;
asc升序 des降序
按照整张表的第二列排序:
select base_cost,unit_cost from costorder by 2;
select 后面跟的2是常量
select 2 from cost;
单行单列
select 2*2 from dual;
select upper('abc') fromdual;//ABC
select sysdate from dual;//查时间
alter session set nls_date_format='yyyy-mm-ddhh24:mi:ss';//修改时间
drop table slf purge;
字符大小敏感,日期格式敏感
要一个日期值,to_date
处理一个date类型的值,为了获得时间信息,to_char
select create_date,os_usernamefrom service where to_char(create_date,'fmmm')='03';//加上fm表示去掉空格和前倒立
select to_number('ab','xx')fromdual; 16*10+11
number 可以定义宽度
date 一定不能定义宽度
archar2必须定义宽度
char 可以不定义宽度(缺省是1)
字符大小写敏感 varchar2对空格是敏感的
select * from account;
select * from cost;
select * from service;
selectreal_name,create_date,idcard_no,birthdate,telephone from account;
select base_cost,base_durationfrom cost where base_cost=5.9;
selectbase_cost*12,base_duration*12 ann_duration from cost where base_cost=5.9;
selectbase_cost*12,base_duration*12 from cost where base_cost*12=70.8;
select base_duration*12 from costwhere base_cost=70.8/12;
select unix_host from servicewhere os_username='huangr';
select unix_host from servicewhere upper(os_username) = 'HUANGR';
select unix_host from servicewhere lower(os_username) = 'huangr';
select unix_host from servicewhere "OS_USERNAME" = 'huangr';
select unix_host from servicewhere upper(os_username) = 'HUANGR';
select unix_host from servicewhere lower(os_username) = 'huangr';
select unix_host from servicewhere initcap(os_username) = 'Huangr';
select unix_host from servicewhere upper(os_username) = 'HUANGR';
select unix_host from servicewhere lower(os_username) = 'huangr';
select base_cost from cost wherebase_cost>=5 and base_cost<=10;
select base_cost from cost wherebase_cost between 5 and 10;
select base_cost from cost wherebase_cost = 5.9 or base_cost=8.5 or base_cost=10.5;
select base_cost from cost wherebase_cost in(5.9,8.5,10.5);
select base_cost , base_durationfrom cost where base_cost = any(5.9,8.5,10.5);
select os_username,unix_host fromservice where os_username like 'h%';
select os_username from service;
select os_username,unix_host fromservice where os_username like 'h\_%' escape '\';
select base_cost,unit_cost
from cost
where unit_cost is null;
select base_cost,unit_cost
from cost
where unit_cost is not null;
select base_cost,unit_cost fromcost
where nvl(base_cost,0) notin(5.9,8.5,10.5);
select base_cost,unit_cost fromcost
where base_cost <>5.9 andbase_cost^=8.5 and base_cost!=10.5;
select base_cost,unit_cost fromcost
where base_cost notin(5.9,8.5,10.5) or base_cost is null;
select base_cost,unit_cost fromcost
where base_cost in (5.9,8.5,10.5)
or base_cost is null;
select os_username,create_datefrom service order by create_date;
select os_username,create_date fromservice order by create_date desc;
select base_cost from cost orderby base_cost desc;
select base_cost*12,name fromcost order by base_cost*12 desc;
select base_cost,unit_cost fromcost order by 2;
select 2 from cost;
select 2*2 from dual;
select upper('abc') from dual;
select unix_host,create_date fromservice
order by unix_host,create_datedesc;
create table slfslf(c1 number,c2number(6),c3 number(4,3),c4 number(3,-3),c5 number(2,4));
insert into slfslf(c1,c2) values(15000,2222);
select * from slfslf;
insert into slfslf values(1,2222,2.222,333033.,0.0042);
insert into slfslf values(2,555555,5.666,3333,0.0099);
insert into slfslf values(2,555555,5.6666,3333,0.0099);
update slfslf set c3=9.999 wherec1=15000;
select round(base_cost/30,1),round(base_cost/30),
trunc(base_cost/30),trunc(base_cost/30,1)
from cost;
select sysdate from dual;
alter session setnls_date_format='yyyy-mm-dd hh24:mi:ss';
select create_date from service;
create table slf (c1 date);
insert into slf values('2008-05-23 14:22:21');
//insert into slfvalues(to_date('1-september-08','DD-MON-RR'));
insert into slf values(to_date('2008-01-01','yyyy-mm-dd'));
select * from slf;
select c1 from slf;
selectto_char(c1,'DD-MON-RR')from slf;
insert into slf values (to_date('200101 01','yyyy mm dd'));
select to_char(c1,'yyyy')fromslf;
insert into slfvalues(to_date('2008-08-08 08:08:08','yyyy-mm-dd hh24:mi:ss'));
select to_char(c1,'yyyy-mm-ddhh24:mi:ss')from slf;
insert into slfvalues('2013-10-12 03:40:20');
select to_char(c1,'yyyy-mm-ddhh:mi:ss')from slf;
select create_date,os_usernamefrom service where to_char(create_date,'fmmm')='3';
select to_number('ab','xx')fromdual;
selectbase_cost,nvl(to_char(unit_cost),'no unit cost') from cost;
列出基础资费
select base_cost,nvl(to_char(unit_cost),'nonuit cost')from cost;
列出昨天今天和明天
alter session set nls_date_format='yyyy mm dd hh24:mi:ss';
selectsysdate-1,sysdate,sysdate+1 from dual;
select sysdate,sysdate+1/144 fromdual;
列出主机,用户名,以及开通的多长时间,并按照开通时间排序
select unix_host,os_username,create_date,round(sysdate-create_date)days
from service order by 4 desc;
//设置日期格式此是默认的
alter session setnls_date_format='DD-MON-RR';
alter session setnls_language='AMERICAN';
半年后
select add_months('01-JAN-08',6)from dual;
输出星期几(字符格式)
select to_char(sysdate,'DAY')from dual;
输出95-9-8的下个星期五
selectnext_day('08-SEP-95','FRIDAY') from dual;
输出当月的最后一天
select last_day(sysdate)fromdual;
alter session set nls_territory =america;
select add_months(sysdate,-1)from dual;//上个月
select add_months(sysdate,1) fromdual;//下个月
select last_day(sysdate) fromdual;//最后一天
selectto_char(last_day(sysdate),'DAY')from dual;//星期几
//base_duration 为20时unit_cost加0.05,base_duration为40时unit_cost加0.03
方法1
select case when base_duration =20 then unit_cost + 0.05
when base_duration = 40 thenunit_cost + 0.03
else unit_cost
endnew_unit_cost,base_duration,unit_cost
from cost;
方法2
selectdecode(base_duration,20,unit_cost+0.05,
40,unit_cost+0.03,
unit_cost)
new_unit_cost,base_duration,unit_cost
from cost;
函数
单行函数
数据函数 number varchar2 char date
数值函数 round trunc
字符函数 upper lower initcap length trim
日期函数 add_months months_between last_day
转换函数 to_date to_char to_number
一般函数 nvl decode
表达式 case when
环境设置 session
NetCTOSS 报表
avg 平均值 number
sum 求和 number
count 计数
max 最大值 number
min 最小值 number
组函数的返回值
1 所有的非空值的处理,返回值不为null
2 处理值都为null,count为0,其他都为null
语法顺序
select from where group by havingorder by
执行顺序
from where group byhaving select order byselect(对数据处理)
from(数据源:表)
where(选择操作:过滤行记录)
group by(分组)
having(过滤组记录)
order by(排序对象,select)
1. 当月包在线时长为20小时,单位费用涨5分,为40小时涨3分,其他不变(用UNION ALL实现)
select case when base_durationbetween 20 and 40
then unit_cost+0.05
when base_duration >40
then unit_cost+0.03
else unit_cost
endnew_unit_cost,unit_cost,base_duration
from cost;
2 月包在线时长在40到100之间,月固定费用涨5角,月包在线时长大约100小时,月固定费用涨3角,其余不变
select case when base_durationbetween 40 and 100
then base_cost + 0.05
when base_duration<40
then base_cost
else
base_cost+0.03
endnew_base_cost,unit_cost,base_cost,base_duration
from cost;
3 huangrong的推荐人
select real_name, idcard_no
from account
where id in(select recommender_id
from account
where real_name='huangrong');
4 huangrong推荐了谁
select real_name,idcard_no
from account
where recommender_id in(select id
from account
wherereal_name='huangrong');
5 那些客户推荐了新客户又被老客户推荐
select real_name,idcard_no
from account
where recommender_id is not null
and id in (select recommender_id
from account);
6 哪些用户没被推荐,也没推荐别人
select real_name,idcard_no
from account
where recommender_id is null
and id not in(selectnvl(recommender_id,0)
from account);
7 那些os帐号的开通天数比同一台上unix服务器上的平均开通天数长
selectunix_host,os_username,create_date
from service o
whereround(sysdate-create_date)>(select round(avg(sysdate-create_date))
from servicei
wherei.unix_host=o.unix_host);
关联子查询:
子查询引用主查询的列
8 哪些客户是推荐人
select real_name,idcard_no
from account o
where exists (select 1 fromaccount i
where o.id=i.recommender_id);
9 哪些客户开通了远程登录业务
select real_name,idcard_no
from account
where exists(select 1 fromservice
whereaccount.id=service.account_id);
10 哪些客户没有申请远程登录业务
select real_name,idcard_no
from account
where not exists(select 1 fromservice
whereaccount.id=service.account_id);
11 哪些客户不是推荐人
select real_name,idcard_no
from account o
where not exists(select 1 fromaccount i
where o.id=i.recommender_id);
子查询:
非关联子查询 in,not in:
单列子查询
多列子查询(多列同时比较)
关联子查询 exists,not exists
主属性:记录的唯一标识 id 约束 主键
idunix_host,os_username,,,account_id real_name,idno
非主属性 account_id 和real_name
real_name依赖account_id
组合问题
select tabname1.colname1,tabname2.colname2
from tabname1 join tabname2
on tabname1.colname2=val1
and tabname1.colname1=tabname2.colname2;
from on(过滤 表)joinon(内连接)select
from(t1 t2)-->t1表过滤-->过滤后的结果集跟t2内连接
哪些客户在unix服务器上申请了远程登录
selecta.real_name,a.id,s.account_id,s.os_username
from account a cross join services
where a.id=s.account_id;
哪些客户在unix服务器上申请了远程登录
selectaccount.real_name,service.account_id
from account join service
on account.id=service.account_id;
客户huangrong在那些unix服务器上申请了远程登录
selecta.id,a.real_name,s.unix_host
from account a join service s
on a.real_name='huangrong'
and a.id=s.account_id;
列出客户姓名以及开通的远程登录的数量
selecta.real_name,count(s.os_username)
from account a join service s
on a.id=s.account_id
group by a.real_name;
先连接(记录数多),再分组,再计算
select a.real_name,s.cnt
from account a join(selectaccount_id ,count(*) cnt
from service group byaccount_id)s
on a.id=s.account_id;
先分组,再计算,结果集做内连接
先执行s,s和account 做内连接
列出每台中比开通天数比平均开通天数大的
selecta.create_date,a.os_username,s.days
from service a join(selectunix_host,round(avg(sysdate-create_date))days
from service group byunix_host)s
on a.unix_host=s.unix_host
and round(sysdate-a.create_date)> s.days;
列出客户姓名以及他的推荐人
select a.id,a.real_namerecommendername,s.real_name
from account a join(selectreal_name,recommender_id
from account)s
on a.id=s.recommender_id;
select t1.real_name client,
decode(t2.id,t1.id,'norecommender',t2.real_name) recommender
from account t1 join account t2
on nvl(t1.recommender_id,t1.id) =t2.id;
哪些客户是推荐人
select distinct t2.real_name
from account t1 join account t2
ont1.recommender_id=t2.id;关联子查询
主表和子表之间建关联,两张表的列写成表达式=
account service a.id=s.account_id
service cost s.cost_id=c.id
内连接
主表:驱动表
子表:匹配表
驱动表和匹配表建关联,两张表的列写成表达式=
两张不同表的记录关系 一对多
同一张表的记录关系 一对多(一个客户可以推荐多个客户)
同一张表的记录关系叫自连接
外连接
左外连接,右外连接
跟内连接的区别:
驱动表是固定的
驱动表的所有记录都在结果集里
from t1 lef (outer)join t2 //t1是驱动表
on t1.c1=t2.c2
外连接的结果集:是内连接的结果集+t1表中不匹配的记录和一条null记录(按t2表的结构)的组合
from t1 right (outer) joint2 //t2是驱动表
on t1.c1=t2.c2
from t1 full join t2
on t1.c1=t2.c2
列出客户姓名以及推荐人
select t1.real_nameclient,t2.real_name recommender
from account t1 join account t2
onnvl(t1.recommender_id,t1.id)=t2.id;
列出客户姓名以及推荐人
select t1.real_name client,
decode(t2.id,t1.id,'Norecommender',t2.real_name) recommender
from account t1 join account t2
onnvl(t1.recommender_id,t1.id)=t2.id;
select t1.id,t1.real_nameclient,nvl(t2.real_name,'No recommender') recommender
from account t1 left join accountt2
on t1.recommender_id = t2.id;
列出顾客开通那些远程登录
selecta.id,a.real_name,s.unix_host
from account a left join services
on a.id=s.account_id;
列出顾客开通那些远程登录
select a.id,a.real_name,s.*
from account a left join services
on a.id=s.account_id;
列出每个顾客都开通了多少远程登录(count跟匹配表里的非空列)
select max(a.id),max(a.real_name),count(s.cost_id)
from account a left join services
on a.id=s.account_id
group by a.id;//groupby 后跟驱动表中的列
select a.real_name,nvl(s.cnt,0)
from account a left join(selectaccount_id ,count(id) cnt
from service
group by account_id)s
on a.id=s.account_id;//效率高
left join所有的客户(申请业务的客户+没有申请业务的客户)
目的:降低表连接的数据量
那些人不是推荐人
select t1.real_name,t2.real_name
from account t1 left join accountt2
on t1.id =t2.recommender_id
where t2.id is null;
from t1 left join t2
on t1.c1=t2.c2
and t2.c3=''
在外连接之前对匹配表作过滤
from t1 t2 -->对t2过滤-->外连接
对匹配表的过滤弱项发生在连接之前,用on过滤
from t1 left join t2
on t1.c1=t2.c2
where t2.c1 is null
from t1 t2-->外连接-->where通过t2的列对外连接的结果集过滤
对驱动表的过滤必须用where子句实现
内连接解决问题:
匹配
外连接解决问题:
1 . 匹配问题+不匹配问题(一个都不能少)
2. 不匹配问题(outer join+where匹配表.非空列 is null)-->not in,not exists
外连接的执行顺序
先将表进行外连接错作,再外连接的结果集用where子句进行过滤,最后用select 声称结果
哪些服务器上没有os帐号weixb
select h.id,s.os_username
from host h left join service s
on h.id=s.unix_host
and s.os_username='weixb'
where s.os_username is null;
select h.id,s.os_username
from host h left join(selectunix_host,os_username
from service)s
on h.id=s.unix_host
and s.os_username='weixb'
where s.os_username is null;
列出那个人属于那个年龄段
selecta.id,a.real_name,round((sysdate-a.birthdate)/365),s.name
from account a join age_segment s
onround((sysdate-a.birthdate)/365) between s.lowage and s.hiage;
huangrong的年龄段
selecta.id,a.real_name,round((sysdate-a.birthdate)/365),s.name,s.lowage,s.hiage
from account a join age_segment s
onround((sysdate-a.birthdate)/365) between s.lowage and s.hiage
where a.real_name='huangrong';
列出每个年龄段有多少客户
selectmax(s.name),count(a.real_name)
from age_segment s left join account a
on round((sysdate-a.birthdate)/365)between s.lowage and s.hiage
group by s.id;
各类连接的应用场合
交叉连接(cross join)
笛卡尔积
内连接(inner join)
解决匹配问题
1 等值连接 =
2 非等值连接 > <
3 自连接
外连接(outer join)
解决不匹配问题
表的所有记录出现在结果集
集合
union/union all 并集(去重)/并集(不去重)
intersect 交集 (不重复)
minus 集合1-集合2
当月保在线时常为20小时单位费用涨5分,为40小时单位费用涨3分,其他不变
selectbase_duration,unit_cost+0.05
from cost
where base_duration=20
union all
selectbase_duration,unit_cost+0.03
from cost
where base_duration=40
union all
select base_duration,unit_cost
from cost
where base_duration not in(20,40)
or base_duration is null;
列出客户姓名以及推荐人(包含所有的客户)
select t2.real_name ,t1.real_namerecommender
from account t1 join account t2
on t1.id=t2.recommender_id
union all
select real_name,'no recommender'
from account
where recommender_id is null;
列出‘sun280’和'sun-server'用了那些相同的资费
select s.cost_id
from host h join service s
on h.id=s.unix_host
and h.name='sun280'
intersect
select s.cost_id
from host h join service s
on h.id=s.unix_host
and h.name='sun-server';
那些服务器上没有开通远程登录
select id
from host
minus
select h.id
from host h join service s
on h.id =s.unix_host
group by h.id;
找出第一列
select rownum,real_name
from account where rownum=1;
select rownum,real_name
from account
where rownum between 1 and 5;
rownum只能找从1开始的数据
找出4-6条记录
方法1:
select rownum,real_name fromaccount where rownum<=6
minus
select rownum,real_name fromaccount where rownum<=3;
方法2:
select real_name
from (select rownum rm,real_name
from account where rownum <= 6) t
where t.rm>=4;
最早开通netctoss系统的前三个客户
selectreal_name,create_date,rownum
from (select real_name,create_date
from account order by create_date)
where rownum <=3;第4到第6位开通的用户
select rm,real_name,create_date
from (select rownum rm,real_name,create_date
from account
order by create_date)s
where rm between 4 and 6;
pl/sql课程
jdbc
service_detail具体登录信息,详单
pl/sql项目课程 计费月出帐
列出每个客户申请了那些资费政策
方法1
select ss.id,ss.real_name,ss.cost_id,c.name
from cost c join(selectc.id,c.real_name,a.cost_id
from account c join(selectaccount_id,cost_id,unix_host
fromservice)a
on a.account_id=c.id)ss
on c.id=ss.cost_id;
方法2
select a.real_name,c.name
from account a join service s
on a.id=s.account_id
join cost c
on c.id=s.cost_id
create table sfl(
c1 number constraint sfl_c1_pkprimary key,
c2 number);
insert into sfl values(1,1);
insert into sfl values(1,1);//uniqueconstraint (JSD1303_1.SFL_C1_PK) violated错误 用户.约束名(JSD1303_1.SFL_C1_PK)
主键约束:primary key
必须唯一并且不为空
列级约束:create table sfl(
c1 number constraint sfl_c1_pkprimary key,
c2 number);
表级约束:create table sfl(
c1 number(2),
c2 number,
constraint sfl_c1_pk primarykey(c1));
create table stu_cou(
sid number(4),
cid number(2),
constraint stu_cou_sidcid_pk primary key(sid,cid),
score number(3));//联合约束
给存在的表加约束
alter table account add constraintaccount_id_pk primary key(id)
唯一键约束:unique key
列名+数据类型+constraint 表名_列名_ukunique
不允许重复
可以插入多个null
create table test(
c1 number(3) constraint test_c1_pk primary key,
c2 number(2),
c3 number(4),
constraint test_c3_uk unique(c2,c3));//c2和c3组合唯一
非空约束:not null
列名+数据类型+not null
外键约束:references foreign key
create table child(
c1 number(3)constraint child_c1_pkprimarykey,
c2 number(2) constraint child_c2_fk referencesparent(1));//表child中的c2列要从parent去取得
被引用的表:父表parent pk
定义外键的表:子表child fk 可以重复
保证一对多关系的实现
在子表的一列上定义外键:外键列
外键列要引用父表中的一列,要求这列唯一特性(pk,uk)
1 先create parent table,被引用列必须保证唯一(pk,uk),再create child table,建fk列
2 先insert into parenttable,再insert into child table
3 先delete from child,再deletefrom parent
4 先drop child tble,再dropparent table
drop table parent cascade constraints purge;//删除父表和子表之间的外键联系,并且删除父表
create table child1(
c1 number primary key,
c2 number references parent(c1)
on delete cascade);//加on delete cascade 时可以直接用drop parentwhere c1=2,将父表和子表中对应的记录同时删除
create table child2(
c1 number primary key,
c2 number references parent(c1)
on delecte set null);//删除drop parent where c1=2,删除父表中的记录,并且将子表的c2=2的记录设置为c2=null
检查约束:check
列名+数据类型+constraints+表名_列名_ckchect (表达式);
create table child(c1number(3)constraint child_c1_pk primarykey,
c2 number(2) constraintchild_c2_fk references parent(1));
create table stlt_cou(
suid number,
cuid number,
constraint stlt_cou_suidcuid_pkprimary key(suid,cuid),
score number);
create table childd(
c1 number(2) constraintchildd_c1_pk primary key,
c2 number(3) constraintchildd_c2_fk references parentt(c1));
多对多
增加一张中间表,两个fk,fk引用多对多的两张表。两个一对多,从而实现多对多
事物transaction
commit(提交) --》TCL
transaction=dmls+commit/rollbanck
dmls
create table(ddl自动提交)
数据库中有很多session,每个session只有一个活动事物(未commit)
事物隔离级别
pk uk fk ck nn
1 列上多个约束
1 列定义在多个列上
1对多关系 pk、uk fk 违反3范式
多对多关系 增加一张表,定义2个fk,违反2范式
分开:没有数据冗余,没有数据不一致,dml的负担,数据记录很纯粹,select 作join操作,规范化
合表:dml负担重,select简单,快,去规范化做法
fk pk pk
name id |id name
zs 1 1 ls
sql脚本(放在跟数据库建立连接的本机上)
//创建 slf_account表
create table slf_account(
id number(9) ,
recommender_id number(9),
login_name varchar2(30) not null,
login_passwd varchar2(8) notnull,
status char(1) not null,
create_date date default sysdate,
pause_date date,
clost_date date,
real_name varchar2(20) not null,
idcard_no char(18) not null,
birthdate date,
gender char(1) not null,
occupation varchar2(50),
telephone varchar2(15) not null,
email varchar2(50),
mailaddress varchar2(50),
zipcode char(6),
qq varchar2(15),
last_login_time date,
last_login_ip varchar2(15),
constraint slf_account_id_pkprimary key(id),
constraintslf_account_recommender_id_fk foreign key(recommender_id) referencesslf_account(id),
constraint slf_account_status_ckcheck(status in(0,1,2)),
constraintslf_account_idcard_no_uk unique(idcard_no),
constraint slf_account_gender_ckcheck(gender in(0,1)));
//创建slf_cost表
create table slf_cost(
id number(4) ,
name varchar2(50) not null,
base_duration number(11),
base_cost number(7,2),
unit_cost number(7,4),
status char(1) not null,
descr varchar2(100),
creatime date default sysdate,
startime date,
constraint sl_cost_id_pk primarykey(id),
constraint sl_cost_statuscheck(status in (0,1)));
//创建slf_service表
create table slf_service(
id number(10),
account_id number(9) not null,
unix_host varchar2(15) not null,
os_username varchar2(8) not null,
login_passwd varchar2(8) notnull,
status char(1) not null,
create_date date default sysdate,
pause_date date,
close_date date,
cost_id number(4) not null,
constraint slf_service_id_pkprimary key(id),
constraintslf_service_account_id_fk foreign key(account_id)references slf_account(id),
constraintslf_service_host_username_uk unique(os_username,unix_host),
constraint slf_service_status_ckcheck (status in(0,1,2)),
constraint slf_service_cost_id_fkforeign key(cost_id) references slf_cost(id)
);
//创建slf_host表
create table slf_host(
id varchar2(15) primary key,
name varchar2(20) not null,
location varchar2(20)
);
//创建slf_service_detail表
create table slf_service_detail(
id number(11) ,
service_id number(10) not null,
client_host varchar2(15),
os_username varchar2(8),
pid number(11),
login_time date,
logout_time date,
duration number(20,9),
cost number(20,6),
constraintslf_service_detail_id_pk primary key(id),
constraintslf_service_detail_sid_fk foreign key(service_id)references slf_service(id)
);
//创建slf_fee_log表
create table slf_fee_log(
log_date date not null,
service_id number(10),
fee_month char(6),
descr varchar2(500)
);
//创建slf_month_duration表
create table slf_month_duration(
service_id number(10),
month_id char(6),
service_detail_id number(11),
sofar_duration number(11)
);
//创建slf_bill表
create table slf_bill(
id number(11),
account_id number(9)not null,
bill_month char(6)not null,
cost number(13,2) not null,
payment_mode char(1),
pay_state char(1) default 0,
primary key(id),
foreign key(account_id)referencesslf_account(id),
check(payment_mode in(0,1,2,3)),
check(pay_state in(0,1))
);
//创建slf_bill_item表
create table slf_bill_item(
item_id number(11),
bill_id number(11) not null,
service_id number(10) not null,
cost number(13,2),
primary key(item_id),
foreign key(bill_id)referencesslf_bill(id),
foreign key(service_id)referencesslf_service(id)
);
//创建slf_role_info表
create table slf_role_info(
id number(11),
name varchar2(20)not null,
primary key(id)
);
INSERT INTO SLF_COST VALUES(1,'5.9元套餐',20,5.9,0.4,0,'5.9元20小时/月,超出部分0.4元/时',DEFAULT,NULL);
INSERT INTO SLF_COST VALUES(2,'6.9元套餐',40,6.9,0.3,0,'6.9元40小时/月,超出部分0.3元/时',DEFAULT,NULL);
INSERT INTO SLF_COST VALUES(3,'8.5元套餐',100,8.5,0.2,0,'8.5元100小时/月,超出部分0.2元/时',DEFAULT,NULL);
INSERT INTO SLF_COST VALUES(4,'10.5元套餐',200,10.5,0.1,0,'10.5元200小时/月,超出部分0.1元/时',DEFAULT,NULL);
INSERT INTO SLF_COST VALUES (5,'计时收费',null,null,0.5,0,'0.5元/时,不使用不收费',DEFAULT,NULL);
INSERT INTO SLF_COST VALUES (6,'包月',null,20,null,0,'每月20元,不限制使用时间',DEFAULT,NULL);
commit;
ALTER SESSION SET NLS_DATE_FORMAT= 'yyyy mm dd hh24:mi:ss';
INSERT INTOSLF_ACCOUNT(ID,RECOMMENDER_ID,LOGIN_NAME,LOGIN_PASSWD,STATUS,CREATE_DATE,
REAL_NAME,BIRTHDATE,IDCARD_NO,TELEPHONE,GENDER)
VALUES(1005,NULL,'taiji001','256528',1,'200803 15','zhangsanfeng','19430225','410381194302256528',13669351234,1);
INSERT INTOSLF_ACCOUNT(ID,RECOMMENDER_ID,LOGIN_NAME,LOGIN_PASSWD,STATUS,CREATE_DATE,
REAL_NAME,BIRTHDATE,IDCARD_NO,TELEPHONE,GENDER)
VALUES(1010,NULL,'xl18z60','190613',1,'200901 10','guojing','19690319','330682196903190613',13338924567,0);
INSERT INTOSLF_ACCOUNT(ID,RECOMMENDER_ID,LOGIN_NAME,LOGIN_PASSWD,STATUS,CREATE_DATE,
REAL_NAME,BIRTHDATE,IDCARD_NO,TELEPHONE,GENDER)
VALUES(1011,1010,'dgbf70','270429',1,'200903 01','huangrong','19710827','330902197108270429',13637811357,0);
INSERT INTOSLF_ACCOUNT(ID,RECOMMENDER_ID,LOGIN_NAME,LOGIN_PASSWD,STATUS,CREATE_DATE,
REAL_NAME,BIRTHDATE,IDCARD_NO,TELEPHONE,GENDER)
VALUES(1015,1005,'mjjzh64','041115',1,'201003 12','zhangwuji','19890604','610121198906041115',13572952468,1);
INSERT INTOSLF_ACCOUNT(ID,RECOMMENDER_ID,LOGIN_NAME,LOGIN_PASSWD,STATUS,CREATE_DATE,
REAL_NAME,BIRTHDATE,IDCARD_NO,TELEPHONE,GENDER)
VALUES(1018,1011,'jmdxj00','010322',1,'201101 01','guofurong','199601010322','350581200201010322',18617832562,1);
INSERT INTOSLF_ACCOUNT(ID,RECOMMENDER_ID,LOGIN_NAME,LOGIN_PASSWD,STATUS,CREATE_DATE,
REAL_NAME,BIRTHDATE,IDCARD_NO,TELEPHONE,GENDER)
VALUES(1019,1011,'ljxj90','310346',1,'201202 01','luwushuang','19930731','320211199307310346',13186454984,0);
INSERT INTOSLF_ACCOUNT(ID,RECOMMENDER_ID,LOGIN_NAME,LOGIN_PASSWD,STATUS,CREATE_DATE,
REAL_NAME,BIRTHDATE,IDCARD_NO,TELEPHONE,GENDER)
VALUES(1020,NULL,'kxhxd20','012115',1,'201202 20','weixiaobao','20001001','321022200010012115',13953410078,1);
COMMIT;
select * from slf_account;
INSERT INTO SLF_HOST VALUES('192.168.0.26','sunv210','beijing');
INSERT INTO SLF_HOSTVALUES('192.168.0.20','sun-server','beijing');
INSERT INTO SLF_HOST VALUES('192.168.0.23','sun280','beijing');
INSERT INTO SLF_HOST VALUES('192.168.0.200','ultra10','beijing');
COMMIT;
INSERT INTO SLF_SERVICE VALUES(2001,1010,'192.168.0.26','guojing','guo1234',0,'2009 03 1010:00:00',null,null,1);
INSERT INTO SLF_SERVICE VALUES(2002,1011,'192.168.0.26','huangr','huang234',0,'2009 03 0115:30:05',null,null,1);
INSERT INTO SLF_SERVICE VALUES(2003,1011,'192.168.0.20','huangr','huang234',0,'2009 03 0115:30:10',null,null,3);
INSERT INTO SLF_SERVICE VALUES(2004,1011,'192.168.0.23','huangr','huang234',0,'2009 03 0115:30:15',null,null,6);
INSERT INTO SLF_SERVICE VALUES(2005,1019,'192.168.0.26','luwsh','luwu2345',0,'2012 02 10 23:50:55',null,null,4);
INSERT INTO SLF_SERVICE VALUES(2006,1019,'192.168.0.20','luwsh','luwu2345',0,'2012 02 10 00:00:00',null,null,5);
INSERT INTO SLF_SERVICE VALUES(2007,1020,'192.168.0.20','weixb','wei12345',0,'2012 02 1011:05:20',null,null,6);
INSERT INTO SLF_SERVICE VALUES(2008,1010,'192.168.0.20','guojing','guo09876',0,'2012 02 11 12:05:21',null,null,6);
COMMIT;
grant connect,resource tojsd1303;//给用户授角色
connect,resource是角色的名字
角色:一堆权限的集合
create role connect;
grant create table to connect;
grant create index to connect;
给用户授系统权限
grant create table to jsd1303
//删除主键约束
alter table test drop primary keycascade;
//显示表的所有约束以及约束名
select constraint_name,constraint_type
from user_constraints
where table_name='TEST';
非空改空
alter table test modify(c1 null);
空改非空,修改之前保证此列中所有记录不为空
alter table test modify(c1 notnull);
删除约束
alter table test drop constraintcon_name;
//查找slf_service表中的约束名
select constraint_name,constraint_type
from user_constraints
where table_name='SLF_SERVICE';
//查找slf_service表中的约束名以及对应的列名
selectconstraint_name,column_name
from user_cons_columns
where table_name='SLF_SERVICE';
service 每个unix服务器的telnet服务,在unix服务器上的注册信息
service_detail :每个os帐号登录登出信息,详细信息
关系:数量 几对几
紧密程度 可以/必须
一个telnet服务可以包含多个详单信息
一条详单信息必须属于一个telnet服务
一个客户可以申请多个telnet服务,一个telnet服务可以有多条详单信息
一条详单信息必须属于一个telnet 服务,一个telnet 服务必须属于一个客户
account(id pk) service(idpk,account_id fk not null)
service(id pk) service_detail(idpk,service_id fk not null)
用户,权限 多对多
database object 数据库对象
table 表
synonym 同义词
create synonym account fortarena.account;
view 视图
index 索引
sequence 序列号
create table(子查询)
//建表
create table service_20
as
select * from service
where unix_host='192.168.0.23';
create table service_20
as
select unix_host,os_username fromservice
where unix_host='192.168.0.23';
create tableservice_20(unix_host,days)
as
selectunix_host,sysdate-create_date from service
where unix_host='192.168.0.23';
这样创建表的时候,只有非空约束可以代过来
创建一张表,表结构于account一致,没有数据
create table account_90slf
as
select * from account
where 1=2;
创建一张表,表结构于account一致,没有数据
create table account_90slf1
as
select * from account
where 1=1;
account_90表中包含所有的90后客户
insert into account_90slf
select * from account
whereto_char(birthdate,'yyyy')between 1990 and 1999;
视图:
create table slf(c1 number,c2number);
insert into slf values(1,1);
insert into slf values(1,2);
insert into slf values(1,3);
insert into slf values(1,4);
create or replace view slf_v1
as
select * from slf
where c1=1;
select * from slf_v1;
在视图添加c1=1的记录的时候,slf也会添加记录
如果在视图添加c1!=1的记录的时候,会在slf中添加的而不是在视图中添加
view 和windows中的快捷方式相似
试图在数据库中不存储数据值,即不占空间
只在系统表中存储对视图的定义
试图实际就是一条select语句
select text from user_views
where view_name='SLF_V1';
结果为:"select "C1","C2" from slfwhere c1=1"
inline-view内嵌视图
from (select c1 from slf)
heap table 堆表
partition table 分区表
每个客户选择了哪些资费标准
create or replace view acc_co
as
select a.real_name,c.name
from account a left join services
on a.id=s.account_id
left join cost c
on s.cost_id=c.id;
select a.real_name,c.name
from account a,service s,cost c
where a.id=s.account_id(+)
and s.cost_id=c.id(+);
from t1,t2
where t1.c1=t2.c2(+) //(+)表示匹配表
==>from t1 left join t2 //t1是驱动表
on t1.c1=t2.c2
哪个unix服务器上没有weixb这个os帐号
select distinct id
from host
minus
select unix_host
from service
where os_username='weixb';
select h.id,s.os_username
from host h,service s
where h.id=s.unix_host(+)
and s.os_username(+)='weixb' 外连接之前过滤
and s.id is null; 外连接之后过滤
简单视图
基于单张表并且不包含函数或表达式的试图,可执行dml语句(即可实现增删改操作)
create or replace view acc_co
as
select * from account where
复杂视图
包含函数 表达式或者分组数据的视图,在该试图上执行dml语句时必须要符合特定条件
在定义复杂视图时必须为函数或者表达式定义别名
create or replace view acc_co
as
select c1,count(*) cnt from
连接视图
基于多个表建立的视图,一般来说不会在该视图上执行insertupdate delete操作
drop table slf,所有依赖该表的对象(view)全部失效
改变view的定义:create or replace view
改变view的状态:alter view view_name compile;
删除view:drop view view_name;
view status valid invalid
create or replace view slf_sl
as
select * from slf
where c1 = 1
with check option;//要求插入的数据必须符合where条件
约束p u c r
with check option 约束vconstraint_type v
with read only//约束o 只读视图,不允许操作
create or replace view slf_sl
as
select * from slf
where c1= 1
with read only;//只读约束
索引index
create index 索引名 on 表名(列名);
create index index_name on table_name(colname);
create database
物理角度:在os上建文件 数据文件(table)、日志文件(transation)、控制文件(数据文件和日志文件)
delete from bigtable
1 表占用的空间不释放
2 保存旧数据到回滚段,时间长
3 数据可恢复(rollback)
truncate table ddl(删除所有记录)
1 释放表占用的空间
2 不会保存旧数据,时间短
3 数据不可恢复(ddl自动提交的)
全表扫描fts
通过rowid扫描
rowid:标识一条记录的物理地址
使用index比fts快-->快速找到rowid,排序-->降低读取data block数量
唯一性索引
create unique index indname ontabname(conname);
非唯一索引
单列索引
联合索引
create table test(c1 numberprimary key,c2 number,c3 number);
create index test_c2_c3_idx ontest(c2,c3);
哪些写法导致索引不可用
1 like和substr
2 where colname is null
3 not in
4 <>
序列:
create table ss(c1 number primarykey);
create sequence sllss start with1110001;
insert into ssvalues(sllss.nextval);
insert into ssvalues(sllss.nextval);
commit;
select * from ss;
insert into ssvalues(sllss.nextval);
rollback;
insert into ssvalues(sllss.nextval);
//结果:1110001 1110002 1110004
select sllss.currval from dual;
//结果:1110004
selectsequence_name,cache_size,last_number from user_sequences;
//结果
sequence_name cache_size last_number
SLLSS 20 1110021
S1 20 1303021
S_ITEM_ID 20 1
PL/SQL(Procedural Language/SQL)是程序
扩展
变量和类型
控制和结构
过程与函数
PL/SQL块
声明部分:DECLARE
执行部分:BEGIN
异常处理:EXCEPTION
END
select 'Hello World' from dual;
打印“Hello World”
begin
dbms_output.put_line('Hello World');
end;//在服务器端打印
set serveroutput on;//设置在客户端打印
begin
dbms_output.put_line('Hello World');
end;
//dbms_output package 包,包里包含过程、函数,过程put_line('Hello World')
调用过程(过程本身没有返回值)
调用函数(函数本身是有返回值)
c/s client/server sqlplus,sqldeveloper,jdbc/oracle server
b/s browseserver b/AS/oracle server
注释符号:
单行注释:--
多行注释:/* */
数据类型
标量类型
数字型 number
number的子类型dec(38),float(38),real(18)
binary_integer(只能用于pl/sql)
字符型varchar2,varchar(长度:1...32767)
string(只能用于pl/sql长度:1...32767)
char(长度:1...32767)
long
日期型
布尔型 boolean
用于存储逻辑值(true,false,null)
不能向数据库中插入boolean类型的数据
不能将列值保存到boolean变量中
只能对boolean变量执行逻辑操作
复合类型
record(记录类型),associativearray,nested table,varray
变量声明
var_name type[constant][not null][:=value];
pl/sql规定没有初始化的变量为null
%type方式
变量具有与数据库表中某列或其他变量相同的类型
declare v_realname varchar2(20);
declare v_realnameaccount.real_name%type;
定义变量,输出他们的值
set serveroutput on;
declare
var_day date := sysdate;
v_daychar varchar2(50);
begin
v_daychar := to_char(var_day,'yyyy mm dd hh24:mi:ss');
dbms_output.put_line('Current Time:'||v_daychar);
end;
if语句:
if then
end if;
if then
else
end if;
if then
elsif then
elsif then
else
end if;
//设置一个布尔类型的变量,真的时候显示'true',假的时候显示'false',否则显示空
declare
t boolean := true;
begin
if t = true then
dbms_output.put_line('true');
elseif t = false then
dbms_output.put_line('false');
else
dbms_output.put_line('null');
end if;
end;
loop循环语句:
exit when 是必须的,否则无法停止
loop
statement1;
statement2;
exit when
end loop;
while循环语句
在while循环中仍可以使用exit或exit when子句
while
statement1;
statement2;
end loop;
for循环语句
每循环一次,变量自动加1,使用关键字
for 循环计数器 in 下限..上限loop
statement1;
statement2;
end loop;
pl/sql
静态sql
可以直接在pl/sql中使用的标准sql
1 dml语句
2 事物控制语句
begin
insert into host(id) values('10.0.0.11');
commit;
end;
动态sql
1 本地动态sql执行ddl语句:
begin
execute immediate'create tabletest(c1 number)';
end;
//把表插入1~1000
begin
execute immediate 'create table ssllff(c1 number)';
end;
begin
for i in 1 .. 1000 loop
insert into ssllff values(i);
end loop;
commit;
end;
匿名块(编译,执行不分)
begin
for i in 1 .. 1000 loop
insert into ssllff values(i);
end loop;
commit;
end;
sql语句编译在sql/sql匿名块编译时发生
--方法二
begin
execute immediate 'create table testslf(c1 number)';
for i in 1 .. 1000 loop
execute immediate 'insert into testslfvalues('||i||')';
end loop;
end;
有名块(编译 执行分开)
procedure
function
select语句的实现
当且仅当返回一条记录
用select....into ....语句实现
declare
v_id number(10) := 1011;
v_realname account.real_name%type;
begin
select real_name into v_realname fromaccount where id=v_id;
end;
--列出id为1011的用户名和身份证号
declare
v_id number(10) := 1011;
v_realname account.real_name % type;
v_idcard_no char(18);
begin
select real_name,idcard_no intov_realname,v_idcard_no from account where id = v_id;
dbms_output.put_line(v_realname);
dbms_output.put_Line(v_idcard_no);
end;
若查询结果是单行多列,用复合类型record记录类型
declare
type t_rec is record --定义t_rec的记录类型,
(realname varchar2(20),
idcard_no char(18),
birthdate date);
v_account t_rec; --v_account是记录类型(t_rec类型)
记录类型变量的属性引用方法是:变量名.属性名
v_account.realname := 'huangrong';
%rowtype用表结构或视图结构定义变量
v_cost cost%rowtype;
--提供客户ID,打印用户的姓名和身份证号,若用户不存在,打印该客户不存在
declare
v_id number(10) := 1111;
type v_rec is record
(realname account.real_name % type,
idcardno account.idcard_no % type);
v_account v_rec;
v_cnt number;
begin
select count(id) into v_cnt from account whereid = v_id;
if v_cnt = 1 then
select real_name,idcard_no into v_accountfrom account where id = v_id;
dbms_output.put_line('['||v_account.realname||' ,'||v_account.idcardno||']');
else dbms_output.put_line('account notexists!');
end if;
end;
返回0条或多条记录: 用cursor实现
cursor SQL语句
隐式cursor:
insert into update delete DMLselect....into.....
属性:目的获取有关隐式cursor的状态信息
sql%isopen boolean dml执行中为true,结束为false
sql%notfound boolean与sql%found相反
sql% found boolean 值为true表示dml操作成功
sql%rowcount 数值 表示dml语句成功执行的数据行数
显式cursor:
declare
cursor c_account is select real_name,idcard_nofrom account;
属性:目的获取有关显式cursor的状态信息
%isopen 布尔 如果cursor是open的,其值为true
%notfound 布尔 如果前一个fetch语句没有返回一行记录,值为true
% found 布尔 如果前一个fetch语句返回记录,值为true
%rowcount 数值 到目前为止,cursor已提取的总行数
declare
cursor c_account is
select real_name,idcard_no from account;
v_acccount c_account % rowtype;
begin
open c_account;
loop
fetch c_account into v_acccount;
exit when c_account % notfound;
dbms_output.put_line(v_acccount.real_name||' '||v_acccount.idcard_no);
end loop;
close c_account;
end;
--方法2 while循环
declare
cursor c_account is
select real_name,idcard_no from account;
v_acccount c_account % rowtype;
begin
open c_account;
fetch c_account into v_acccount;
while c_account%found loop
dbms_output.put_line(v_acccount.real_name||' '||v_acccount.idcard_no);
fetch c_account into v_acccount;
end loop;
close c_account;
end;
--没有记录的时候也不会报错
--方法3 for循环
declare
cursor c_account is
select real_name,idcard_no from account;
begin
for i in c_account loop --i是记录类型
dbms_output.put_line(i.real_name||' '||i.idcard_no);
end loop;
end;
select into 一条记录
单行单列:into 标量记录
单行多列:into record(type isrecord,tabname%rowtype,curname%rowtype)
0条或多条记录:cursor
pl/sql client-->serverprocess(oracletarena)
server process
(pl/sql engine,sql engine)
在pl/sql中如何些下面
DDL:本地动态sql execute immediate
DML:静态sql(直接表达),本地动态sql
用pl/sql实现先建表再插入数据
因为ddl必须用动态sql,所以dml只能用动态sql
表存在,直接插入数据,静态dml
TCL :commit rollback 放在循环外
select:select into+变量 当且仅当返回一条记录
sursor 0 条或多条(不报错)fetch into +变量
变量(标量:单行单列) 复合(record:单行多列)
declare
type 数据类型 record 自定义数据类型
变量
标量 预定义数据类型
复合 自定义数据类型
cursor
collection集合
分类
1 Associative array(关联数组) 又称index-by table用键值访问
2 Nested table 嵌套表
3
关联数组:(赋值打印)
declare
type t_indtab is table of number
index by binary_integer;
v_indtab t_indtab;
begin
v_indtab(1):=1;
v_indtab(2):=2;
v_indtab(10):=10;
v_indtab(5):=5;
dbms_output.put_line(v_indtab(1));
dbms_output.put_line(v_indtab(2));
dbms_output.put_line(v_indtab(10));
dbms_output.put_line(v_indtab(5));
end;
关联数组:(赋值,循环打印)
set serveroutput on;
declare
type t_indtab is table of number
indexby binary_integer;
v_indtab t_indtab;
begin
v_indtab(1):=1;
v_indtab(2):=2;
v_indtab(5):=30;
v_indtab(4):=40;
for i in v_indtab.first .. v_indtab.last loop
if v_indtab.exists(i)then
dbms_output.put_line(v_indtab(i));
endif;
end loop;
end;
关联数组的方法:
exists:
count:
first和last
prior和next
trim
delete
--赋值,循环打印
declare
type t_indtab is table of number
index by binary_integer;
v_indtab t_indtab;
v_index binary_integer;
begin
v_indtab(0):=1;
v_indtab(2):=2;
v_indtab(5):=30;
v_indtab(4):=40;
v_index := v_indtab.first;
while v_index <= v_indtab.last
loop
dbms_output.put_line(v_indtab(v_index));
v_index:=v_indtab.next(v_index);
end loop;
end;
--v_index:=v_indtab.next(v_index);值的改变情况 0 -->2-->4-->5
--account 表中的real_name存入关联数组,下标用帐务帐号id,遍历这个关联数组
declare
cursor c_account is select id,real_name from account ;
v_index binary_integer;
type t_account is table ofvarchar2(20) index by binary_integer;
v_account t_account;
begin
for i in c_account loop
v_account(i.id):=i.real_name;
end loop;
v_index := v_account.first;
while v_index <= v_account.last loop
dbms_output.put_line(v_index||' '||v_account(v_index));
v_index := v_account.next(v_index);
end loop;
end;
--account 表中的real_name,idcard_no存入关联数组,下标用帐务帐号id,遍历这个关联数组
declare
cursor c_account is select id,real_name,idcard_no from account ;
v_index binary_integer;
type namecard is record(
real_name varchar2(20),
idcard_no char(18));
type t_account is table ofnamecard index by binary_integer;
v_account t_account;
begin
for i in c_account loop
v_account(i.id).real_name:=i.real_name;
v_account(i.id).idcard_no:=i.idcard_no;
end loop;
v_index := v_account.first;
while v_index <= v_account.last loop
dbms_output.put_line(v_index||' '||v_account(v_index).real_name
||' '||v_account(v_index).idcard_no);
v_index := v_account.next(v_index);
end loop;
end;
关联数组的初始下标不能为空
关联数组的初始化下标对应的内容不能为空
--是关联数据,其中元素的数据类型是record
select real_name,idcard_no bulkcollect into v_account from account;
--打印每个客户的名字,姓名,年龄以及累计年龄
declare
sumage binary_integer:=0;
type namecard is record(
real_name varchar2(20),
age binary_integer);
type t_account is table ofnamecard index by binary_integer;
v_account t_account;
begin
select real_name,round((sysdate-birthdate)/365) age
bulk collect into v_account
from account;
if v_account.count <> 0 then
for i in v_account.first .. v_account.last
loop
sumage:=sumage+v_account(i).age;
dbms_output.put_line(v_account(i).real_name||' '||v_account(i).age||' '||sumage);
end loop;
else
dbms_output.put_line('no account!');
end if;
end;
Exception
pl/sql错误
1 编译时错误
2 运行时错误
1 oracle错误(ora-xxxxx)
2 pl/sql运行错误
3 用户定义的条件
异常的类型
1 隐式触发
1)oracle预定义异常
(例如:no_data_found(出现在select into 或者引用的时候找不到元素),
too_many_rows(select into行多的异常),
invalid_cursor(fetch一个关闭的cursor),
zero_divide(0不能被除),
dup_val_on_index(唯一性索引异常)
value_error(错误的值引用))
--预定义异常
declare
sumage binary_integer:=0;
type namecard is record(
real_name varchar2(20),
age binary_integer);
type t_account is table ofnamecard index by binary_integer;
v_account t_account;
begin
select real_name,round((sysdate-birthdate)/365) age
bulk collect into v_account
from account where 1= 2;
for i in v_account.first .. v_account.last
loop
sumage:=sumage+v_account(i).age;
dbms_output.put_line(v_account(i).real_name||' '||v_account(i).age||' '||sumage);
end loop;
exception
when value_error then
dbms_output.put_line('no account');
end;
2) 非oracle预定义异常
声明:exception_nameexception;
与oracle错误号关联:pragma exception_init(exception_name,-2291)
捕获异常:whenexception_name then....
2 显式触发
用户自定义异常
1 > 声明异常
2 > 异常发生时用raise触发异常
3 > 异常处理部分捕获异常
子程序sub program
匿名子程序
匿名块不存在数据库中
每次使用时都会进行编译
不能在其他块中相互调用
有名子程序
命名的pl/sql,编译并存存在数据库中,可以在任何需要的地方调用
子程序的组成部分:
子程序头
声明部分
可执行部分
异常处理部分(可选)
有名子程序的分类
procedure:过程
function:函数
package:包
trigger:触发器
创建存储过程
create or replace proceduresllaccountnum
is
v_cnt binary_integer;
begin
select count(id) into v_cnt fromaccount;
dbms_output.put_line('accountnumber is '||v_cnt);
end;
begin
sllaccountnum; --调用sllaccountnum
end;
--过程没有返回值,直接调用
selectobject_name,object_type,status from user_objects;
--存储过程中的参数
create or replace procedurepslfs1
(p_in in varchar2,
p_out out varchar2,
p_inout in out varchar2)
is
v_in varchar2(10);
begin
v_in := p_in||'d';
p_out := p_out||'d';
p_inout := p_inout||'d';
end;
/* in (缺省)in的值写入的值不能发生改变
out 参数不能将值传入,即所有out值都为空
*/
declare
v_in varchar2(10):='abc';
v_out varchar2(10) :='abc';
v_inout varchar2(10) :='abc';
begin
pslfs1('abc',v_out,v_inout);
dbms_output.put_line(v_in);
dbms_output.put_line(v_out);
dbms_output.put_line(v_inout);
end;
提供一个客户编号,返回这个用户的名称年龄
create or replace function sdde(sid number,sage out number)
return varchar2
is
type t_account is record(namevarchar2(20),age binary_integer);
v_account t_account;
begin
select real_name,round((sysdate-birthdate)/365) age into v_account fromaccount where id =sid;
sage:=v_account.age;
return v_account.name;
exception
when no_data_found then
dbms_output.put_line('not found this account');
return null;
end;
declare
age number;
begin
dbms_output.put_line(sdde(1111,age)||age);
end;
pl/sql块
匿名块
有名块 过程
关联数组
select 返回多条记录
cursor while fetch into 变量
变量 集合类型(关联数组 ) 元素类型 记录类型
declare
关联数组类型定义type t_indtab is table of index by
v_indtab t_indtab
begin
cursor while fetch into 变量
select bulk collect into 变量;
遍历关联数组
用关联数组的方法first last nextcount
for i in v_indtab.first ..v_indtab.last 简单 下标连续(下标不连续时效率低,空转) 异常处理
while 效率高(有多少个元素,循环多少次) 没有异常处理
异常处理
预定义异常
非oracle预定义异常
有名块procedure
数据库对象
create or replace procedure
编译存储过程
uer_objects 编译不成功invalid不可以调用
编译成功valid可以调用
调用(执行)存储过程
begin
过程名;
end;
exec 过程名
参数 in out inout
--模式为inout或out的形参对应的实际参数必须是变量
过程本身没有返回值
过程能返回值?能 out inout
in 实参-->形参(过程开始执行)
out 实参< --形参(过程执行结束)
inout实参< -->形参(过程开始执行实参-->形参,过程执行结束形-->实参)
tarena用户
授予对象权限grant select on account to jsd1303;
sys用户
授予系统权限grant create table to jsd1303;
角色
create role rolename;
grant to role;
--通过角色授权
connect:create session,createtable..
--直接授权
grant create table to jsd1303;
jsd1303通过角色role获得权限
role:方便权限管理
role:enable(生效)disable(失效)
alter table test drop primarykey;
alter table test add primarykey(c1);
alter table test disable primarykey;
alter table test enable primarykey;
role:
role enable有权限
role disable没权限
匿名块的编译和执行在一起
有名块编译和执行分开,role在编译和执行时的角色状态不一样(enable disable)
oracle解决办法,所有通过角色授予的系统权限不能用,在存储过程中需要的系统权限必须通过直接授予的方式。
hiloo用户操作jsd1303用户的表
1 jsd1303授予用户hiloo对表的操作权限(dml select)
grant select on test to hiloo;
grant insert on test to hiloo;
hiloo通过任何client程序对jsd1303的表的操作
2 jsd1303 不授予hiloo对表的操作权限,jsd1303创建存储过程(对自己表的操作),jsd1303授予hiloo用户对存储过程的执行权限(jsd1303中存储着对表的操作s1,赋予hiloo用户有s1执行权限)
grant execute on proc1 to hiloo;
--绑定变量(:变量名)
create or replace proceduresdsde(
sid number,sage out number,sname outvarchar2)
is
type t_account is record (
name varchar2(20),age binary_integer);
v_account t_account;
begin
selectreal_name,round((sysdate-birthdate)/365) age
into v_account from account where id =sid;
sage:=v_account.age;
sname:=v_account.name;
exception
when no_data_found then
dbms_output.put_line('not found this account');
end;
variable v_realname varchar2(20)
variable v_age number
execsdsde(1011,:v_age,:v_realname)
print v_realname
print v_age
静态sql
编译存储过程时编译sql语句,预编译,sql语句是在pl/sql编译阶段编译的。
例如
create or replace procedure p1
is
begin
for i in 1 .. 1000 loop
insert into tes values(i);
end loop;
commit;
end;
/* for i in 1 .. 1000 loop
insert into tes values(i)
end loop;
可以解析为insert into tes values(:i)using i
*/
动态sql 编译存储过程时不编译sql语句,执行的时候才编译
create or replace procedure p1
is
begin
for i in 1 .. 1000 loop (statment jdbc)
execute immediate 'insert intotes values('||i||')';
end loop;
commit;
end;
动态绑定sql (preparedstatement)
create or replace procedure p1
is
begin
for i in 1 .. 1000 loop
execute immediate 'insert intotes values(:i)'using i;
end loop;
commit;
end;
----------------------对比
静态sql: insert into tes values(i);减少软分析此说以及硬分析次数
动态sql: execute immediate 'insert into tes values('||i||')';
动态绑定sql : execute immediate 'insert into tes values(:i)'using i; 减少硬分析次数
静态sql性能 > 动态sql
declare
e_notable exception;
pragmaexception_init(e_notable,-942);
begin
execute immediate 'drop tablesssll ';
execute immediate 'create tablesssll(c1 number)';
exception
when e_notable then
execute immediate 'create table sssll(c1number)';
end;
-------------------------------------
declare
v_cnt binary_integer;
begin
select count(*) into v_cnt fromuser_tables where table_name = 'SSSLL';
if v_cnt = 0 then
execute immediate 'create tablesssll(c1 number)';
else
execute immediate 'drop tablesssll ';
execute immediate 'create tablesssll(c1 number)';
end if;
end;
--------------------------------------------------
set serveroutput on
variable j number;
begin
:j:=10;
dbms_output.put_line(:j);需要输入J绑定,结果为绑定的值
end;
print j --10
--------------
create sequece s1
start with 1
maxvalue 5
select sl1.nextval from dual;
-- sequence SL1.NEXTVAL exceedsMAXVALUE and cannot be instantiated
create sequence dsl1
start with 1
maxvalue 5 cycle;
--number to CACHE must be lessthan one cycle
create sequence dsl1
start with 1
maxvalue 5 cache 4 cycle;--catche要小于maxvalue并且比start with大
select dsl1.nextval from dual;--从1到5循环不断
------------------------------------------------
函数function
/*select text user_source wherename='FAC1';--获得fun1的源码*/
create or replace function fac1
(p_in number,p_out out number)
return number
is
begin
p_out:=2;
return p_in;
end;
--调用方法的方式1
declare
a number;
b number:=22;
begin
a:=fac1(10,b);
dbms_output.put_line(a);
end;
--调用方法的方式2
declare
v_out number;
v_fac1 number;
begin
v_fac1:=fac1(10,v_out);
dbms_output.put_line(v_fac1);
end;
---------------------------------
提供客户id,返回用户姓名和年龄,若该客户不存在,返回Null
create or replace function getnameandage2
(p_in number,p_age out number)
return varchar2
is
p_name varchar2(20);
v_errm varchar2(2000);
begin
selectreal_name,round((sysdate-birthdate)/365) age
into p_name,p_age from accountwhere id = p_in;
return p_name;
exception
when no_data_found then
return 'null';
when others then
v_errm:=sqlerrm;
return v_errm;
end;
drop function getnameandage2;
declare
vv_age number;
begin
dbms_output.put_line(getnameandage2(1011,vv_age));
dbms_output.put_line(vv_age);
dbms_output.put_line(getnameandage2(1111,vv_age));
end;
------------------------------------------------
declare
自定义数据类型(复合数据类型记录record,关联数组is table of index by)
变量
cursor
exception
procedure
function
begin
package,package body
1 开发并行,开发效率高
2 程序之间的依赖度底,降低编译程序的次数
create or replace package ppp
is
type t_rec is record(m1 number,m2 varchar2(10));
v_rec t_rec;
procedure pr1;
function fadd(p_in number)return number;
end;
create or replace package bodyppp
is
procedure pr1
is
begin
dbms_output.put_line(v_rec.m1);
end;
function fadd(p_in number)return number
is
begin
return p_in;
end;
end;
begin
ppp.v_rec.m1:=ppp.fadd(10);
ppp.pr1;
end;
------------------------------------------------------
包的优点
1 方便对存储过程和函数的安全性管理
整个报的访问权限只需一次性授权
区分公用 过程和私有过程
2 改善性能
包被首次调用时作为一个 整体全部调入内存
减少多次调用时的磁盘I/O次数
包内定义的变量的范围:session级,只要session不关闭就不会改变
如果重新连接session则,值为null;
--alter package ppp compile;重新编译包
变量
局部变量 declare..begin,functionis ..begin,procedure is ... begin
全局变量(session代码不能重新编译)packageis...end
绑定变量:sqlplus宿主变量
--定义包包含通过用户id调用用户姓名和年龄的函数,以及过程打印函数值的过程
create or replace packageslfgetaccount
is
type t_rec is record(tname varchar2(20),age binary_integer);
v_rec t_rec;
function slfgna(p_id number)return t_rec;
procedure printrec;
end;
create or replace package bodyslfgetaccount
is
function slfgna(p_id number)return t_rec
is
begin
selectreal_name,round((sysdate-birthdate)/365) age
into v_rec from account where id = p_id;
return v_rec;
exception
when no_data_found then
v_rec.tname:='no account';
v_rec.age:=0;
return v_rec;
end;
procedure printrec
is
begin
dbms_output.put_line(v_rec.tname||' '||v_rec.age);
end;
end;
begin
slfgetaccount.v_rec:=slfgetaccount.slfgna(1111);
slfgetaccount.printrec;
end;
--------方法2
create or replace packageslfgaccount
is
type t_rec is record(tname varchar2(20),age binary_integer);
function slfgna(p_id number)return t_rec;
procedure printrec(p_id number);
end;
create or replace package bodyslfgaccount
is
function slfgna(p_id number)return t_rec
is
v_rec t_rec;
begin
selectreal_name,round((sysdate-birthdate)/365) age
into v_rec from account where id = p_id;
return v_rec;
exception
when no_data_found then
v_rec.tname:='no account';
v_rec.age:=0;
return v_rec;
end;
procedure printrec(p_id number)
is
v_rec t_rec;
begin
v_rec:=slfgna(p_id);
dbms_output.put_line(v_rec.tname||' '||v_rec.age);
end;
end;
begin
slfgaccount.printrec(1111);
end;
----------------------------------
触发器trigger
create table ssll(c1 numberprimary key,c2 number);
create or replace triggerslltrigger
before update
on ssll
for each row
declare
begin
end
/*在给ssll表作update之前作declare begin end操作*/
触发时间:update
before update on test for eachrow --行级before触发
before update on test --语句级before触发
after update on test for each row --行级after触发
after update on test --语句级after触发
行级 、语句级触发器的区别
before 语句级 在sql语句执行之前执行一次
before 行级 sql语句影响的每条记录被update delete insert之前执行一次
after 行级 sql语句影响的每条记录被update delete insert 之后执行一次
after 语句级 在sql语句执行之后执行一次
before语句级
before行级
after行级
before行级
after行级
before行级
after行级
。。。。。
after语句级
---------------------------------
create table ssll(c1 numberprimary key,c2 number);
create sequence ssdd1;
create or replace triggerslltrigger
before insert
on ssll
for each row
declare
begin
select ssdd1.nextval into :new.c1 from dual;
end;
insert into ssll(c2) values(2);--1,2
select * from ssll;
insert into ssll values (100,10);--2,10
--------------------------------------------------
create table ppsss(c1 numberprimary key);
create table ccss(c1 number,c2number references ppsss(c1));
create or replace triggerup_cascade
after update on ppsss
for each row
declare
begin
update ccss set c2 = :new.c1 where c2 =:old.c1;
end;
insert into ppsss values(1);
insert into ppsss values(2);
insert into ccss values(1,1);
update ppsss set c1 = 10 wherec1=1;
select * from ccss;