--###################################################################################
/*
版本号: Oracle9i或者Oracle9g---i表示internet, g表示grid
iSqlplus (DBA) URL: http://localhost:5560/isqlplus(/dba)
完全卸载oracle: 卸载完成后, 手工删除项 HKEY_LOCAL_MACHINE/SOFTWARE/ORACLE
服务: OracleService实例名---Oracle核心服务
OracleOraDb10g_home1TNSListener---通过网络访问数据库
OracleOraDb10g_home1iSql*Plus---通过浏览器访问
端口号: Oracle---5560 Sql---1433,1434
登陆: 在cmd中输入 sqlplus; 系统用户名: system 或者 sysdba, 密码:安装时设置
强制登陆: 在cmd中输入 sqlplus / as sysdba
默认帐户: scott 密码:tiger, 默认是locked; hr 密码:tiger
Schema方法: 是与用户关联的表、视图、簇、过程和程序包等对象的命名的集合, 该方案schema在Oracle创建用户时自动创建.
Oracle数据库字典:
USER_*:用户视图,即用户schema中的视图
ALL_*:扩展用户视图,即用户可以访问的视图, 包含自己的用户视图和一个其他的可访问的视图
DBA_*:所有方案的视图
缩写:
DDL(Database Definition Language): 数据库定义语言
DML(Database Manipulation Language): 数据库操作语言
DCL(Database Control Language): 数据库控制语言
DTM(Database Trasaction Management): 数据库事物管理
知识概要:
|---1.查询Select
|
|---2.数据库定义语言DDL: 对表,视图等的操作, 包括create,drop,alter,rename,truncate
|
数据库操作--|---3.数据库操作语言DML: 对记录进行的操作, 包括insert,delete,update
|
|---2.数据库控制语言DCL: 对访问权限等的操作, 包括grant,revoke
|
|---2.数据库事物管理DTM: 对事物的操作, 包括commit,rollback,savepoint
约束: 主键(Primary Key)、外键(Foreign Key)、非空(not null)、唯一(unique)和检查(check)
事物的是由DML(insert,delete,update)开启的, 在Oracle中需要执行commit才能看到DML操作的结果;
而引起事物的提交或结束原因有:
.DTM操作: commit,rollback,savepoint
.系统崩溃宕机: 隐式rollback
.正常: 隐式commit
.DDL和DCL操作: DDL(create,drop,alter,rename,truncate)
DCL(grant,revoke)
备注:
Oracle中, 字符串和日期区分大小写, 且需要用单引号进行表示. 若要输出单引号, 用''表示一个单引号
Oracle中使用||拼接字符串, Sql中使用+拼接字符串
C#数据类型:
整数: sbyte,byte,short,ushort,int,uint,long,ulong
实数: float,double,decimal
字符: char,string
布尔: boolean
日期: datetime
对象: object
Oracle数据类型:
整数: number(38) --n表示位数
字符: char(2000), nchar(1000), varchar2(4000),nvarcahr2(2000), long
日期: date
Sql注入测试串: ' or 1=1 --
解决注入攻击的手段:
. 不拼接字符串, 有字符串操作时, 要留心.
. 使用参数进行赋值, 尽量使用强类型.
. 对用户输入的字符进行过滤.
. 若非用串的话(如:用户名登陆过程), 可以用代码先到数据库中查一下是否有这个名字, 没有则禁止操作
*/
--###################################################################################
--查询系统资源:
--常用命令
set linesize
set pagesize
clear screen
show user
show errors --显示错误, 如在存储过程中显示错误
edit ----可以使用edit(ed)编辑刚才输入的语句, 编辑结束后用"/"提交
list --列出sqlplus缓冲区中的命令, 简写为l
begin
dbms_output.put_line('hello, world!'); --Orcle中输出字符, 注意输出语句在begin和end之间, 且注意分号
end;
--表及表信息
decribe user_tables
select * from user_tables
select table_name from all_tables
select procedure_name from user_procedures --查询存储过程
select * from user_sequences --查询序列
select * from all_sequences
select Seq_Test.nextval from dual --查询下一个递增序列的值
select Seq_Test.currval from dual --查询当前序列的值
--视图
select * from user_views
--查看约束名称、表名字、约束类型及字段名
select table_name, constraint_name, constraint_type, search_condition from User_Constraints --查看表约束
select table_name,constraint_name, column_name from user_cons_columns --查看列约束
select c.table_name,c.constraint_name, u.constraint_type, c.column_name
from user_cons_columns c inner join user_constraints u
on c.constraint_name = u.constraint_name
grant unlimited tablespace to scott --无法将表空间授予角色, 只能授予用户
revoke unlimited tablespace from scott
--用户及用户角色信息
show user
select * from all_users
select username from user_users
select username,default_tablespace from user_users --查看缺省用户表空间
select * from user_role_privs --查看用户具有的角色
--授权及权限
select * from user_sys_privs --授予用户的系统权限
select * from role_sys_privs --授予角色的系统权限
select * from role_tab_privs --授予角色的表的权限
select * from dba_sys_privs where grantee = 'SYS' --查看'SYS'的具体权限, 注意大小写
select grantee,owner,table_name,privilege from dba_tab_privs --查看所有用户的权限
select name from sys.system_privilege_map --查看Oracle提供的系统权限
select * from user_tab_privs_made --用户对象创建时的权限
select * from user_tab_privs_recd --用户对象接收的权限
select * from user_col_privs_made --用户对象创建时列上的权限
select * from user_col_privs_recd --用户对象列接收的权限
--查看一个用户的所有系统权限(包含角色的系统权限)
select privilege from dba_sys_privs where grantee='RESOURCE'
union
select privilege from dba_sys_privs where grantee in (
select granted_role from dba_role_privs where grantee='RESOURCE'
)
select * from dba_roles
create user TestUser identitied by TestUser account unlock
grant create session to TestUser
create role TestUserRole
grant TestUserRole to scott
grant create session, create view, resource, connect to TestUserRole --通常给的用户权限
grant resource, connect to scott
drop user TestUser
revoke create seeion from hr
drop role TestUserRole
revoke resource,connect from TestUserRole
alter user hr identitied by tiger account unlock
--###################################################################################
--创建表, 约束类型: 主键、外键、唯一、check约束、非空约束
-- 注意事项: 序列不保证连续、关键字不必要连续、业务数据不适合作为关键字
drop table T_Event;
drop sequence seq_T_Event;
create sequence seq_T_Event start with 1 increment by 1;
create table T_Event(
seqid number(8),
constraint pk_T_Event primary key(seqid), --单独写约束, 可以方便添加联合主键(在seqid后便添加即可)
title varchar2(200) constraint nn_T_Event_title not null,
startdate date constraint nn_T_Event_startdate not null,
enddate date constraint nn_T_Event_enddate not null,
constraint ck_T_Event_enddate check(enddate > startdate),
detail varchar2(500),
userid number(8),
constraint fk_T_Event_userid foreign key(userid) references T_UserInfo(seqid)
)
drop table T_UserInfo;
drop sequence seq_T_UserInfo;
create sequence seq_T_UserInfo start with 1 increment by 1;
create table T_UserInfo
(
seqid number(8),
constraint pk_T_UserInfo primary key(seqid),
username nvarchar2(30) constraint nn_T_UserInfo_username not null,
constraint uq_T_UserInfo_username unique(username),
create_data date default sysdate
)
--修改表结构
alter table T_Event
add userid number(8)
alter table T_Event
drop column test
--修改表约束
alter table T_Event
add constraint fk_T_Event_userid foreign key(userid) references T_UserInfo(seqid)
--###################################################################################
--创建视图
create or replace view View_DepEmp
as
select last_name Given_Name,salary
from employees e inner join departments d on e.department_id = d.department_id
--###################################################################################
--新增(插入)数据(DML操作, 在commit之后才会提交)
insert into T_Event(seqid,title,startdate,enddate,detail,userid)
values(seq_T_Event.nextval,'吃饭',to_date('2010-11-5','yyyy-mm-dd'),
to_date('2010-12-1 8:30','yyyy-mm-dd hh-mi'),'有人请吃大餐, 不吃白不吃!','1');
insert into T_Event(seqid,title,startdate,enddate,detail,userid)
values(seq_T_Event.nextval,'喝酒',to_date('11-5-2012','mm-dd-yyyy'),
to_date('13-12-2012 12:45','dd-mm-yyyy hh-mi'),'有人请喝酒, 不喝白不喝!','1');
commit
insert into T_UserInfo(seqid,username)
values(seq_T_UserInfo.nextval,'admin');
insert into T_UserInfo(seqid,username)
values(seq_T_UserInfo.nextval,'user');
commit
--删除数据
truncate table T_Event --只删除表的数据
delete from T_Event where title = '喝酒'
commit
--修改数据
update T_UserInfo set username = 'Client' where username='user'; --注意set后边仍为=
commit
--###################################################################################
--查询数据
select distinct department_id, job_id from employees --distinct
select department_id as "部门编号", job_id "职位编号" from employees --起别名的方式as和空格, 注意""
select department_id || ' 联合 ' || job_id as "唯一标识" from employees --别名双引号, 连接字符串用单引号
select first_name,last_name,salary from employees where salary >= 8000 and salary <= 10000
select first_name,last_name,salary from employees where salary between 8000 and 10000
select department_id, job_id from employees where department_id is null
--模糊查询呢: 通配符: %(0-任意字符), _(1个字符),[a,b,c](选择含a或b或c),[^a,b,c](选择不含a或b或c)
select first_name, last_name from employees where last_name like 'D%' or last_name like 'E%'
select first_name, last_name from employees where last_name like('D%') or last_name like('E%')
select first_name, last_name from employees where last_name between 'D' and 'F' --注意这里取左不取右
select first_name, last_name from employees where substr(last_name,1,1) in('D','E')SYSTEM
--嵌套查询(子查询): 分为单行子查询和多行子查询, 区别就是子查询的结果是单条记录还是结果集
--1. dual是系统的虚表, 可以用不需要From的select语句中
--2. rownum成为伪列, 用于生成序号.原理: 生成结果集后, 再加上序号
select next_day(sysdate,3) from dual --返回下周2的日期, 周的计算从1开始
--利用伪列进行分页: 将子查询作为虚拟表再查询
--1. 输出前10条排序后的记录
select rownum,department_name from employees where rownum <= 10 --未排序
select rownum, department_name --排序后的记录, 因为select基本最后执行, 所以select两次
from (
select rownum, department_name
from departments
order by department_name
)
where rownum <= 10
--2. 输出前11-20条排序后的记录
select rn,department_name
from(
select rownum as rn, department_name
from (
select rownum, department_name
from departments
order by department_name
)
)
where rn between 11 and 20 --rownum根据结果集来生成, 一直没有rownum=1的记录, 所以得不到11的记录
--单行子查询: =、>、<
select last_name,salary
from employees
where salary > (select avg(salary) from employees) --子查询结果为单挑记录
--多行子查询: in(在结果集里面即可)、any(符合任一个即可)、all(完全符合才可)
select last_name,salary --在结果集中
from employees
where salary in (select salary from employees where department_id = 110)
select last_name,salary --大于所有的, 也就是大于最大的(替代mssql的top?)
from employees
where salary > all(select salary from employees where department_id = 110)
selet last_name,salary --大于任何一个, 也就是大于最小的
from employees
where salary > any(select salary from employees where department_id = 110)
--###################################################################################
--排序
select distinct department_id, job_id from employees order by job_id desc --默认是升序asc
--###################################################################################
--聚合函数
select sum([sid]) from T_StuScore
select count([sid]) from T_StuScore --count(*)表示记录数, 而count(字段)忽略掉null值
select avg([sid]) from T_StuScore
select max([sid]) from T_StuScore
select min([sid]) from T_StuScore
select distinct(department_id), job_id from employees
select distinct department_id, job_id from employees
--###################################################################################
--分组函数, where用于对记录的筛选, having用于对组的筛选, 并且组函数将忽略结果为null的字段
select gender,Counter = count(*) from T_Stuinfo group by gender
select gender,Counter = count(*) from T_Stuinfo group by gender having count(*) >= 2
--###################################################################################
--表连接: 笛卡尔积(m*n条记录), 内连接, 外连接(左外连接、右外连接、全外连接), 自连接
--内连接: 先从m和n中选择, 然后再连接
select sname,sid,cid,score
from T_StuInfo s inner join T_StuScore c on s.sid = c.sid
--左外连接(左连接): 内连接 + 左表剩余记录(右表记录置null)
select sname,sid,cid,score
from T_StuInfo s left join T_StuScore c on s.sid = c.sid
--右外连接(右连接): 内连接 + 右表剩余记录(左表记录置null)
select sname,sid,cid,score
from T_StuInfo s right join T_StuScore c on s.sid = c.sid
--全外连接(全连接): 内连接 + 左表剩余记录(右表记录置null) + 右表剩余记录(左表记录置null)
select sname,sid,cid,score
from T_StuInfo s full outer join T_StuScore c on s.sid = c.sid
--自连接(全连接): 本表与本表连接, 可以是外连接或内连接
select sname,sid,cid,score
from T_StuInfo s inner join T_StuInfo c on s.sid = c.sid
--###################################################################################
--函数: Oracle中的函数分为单行函数和组函数两种. 组函数用于Group by字句中.
-- 单行函数包括: 字符函数、数字函数、日期函数、Sysdate以及一些其他函数.
--系统函数 注意: 如果要在sqlplus中看到输出, 需要先执行set serveroutput on
begin
--nvl('expression',value)函数, expression为null便用后便的value代替
dbms_output.put_line(nvl(null,0));
dbms_output.put_line(to_char(sysdate));
dbms_output.put_line(to_number(123.567));
dbms_output.put_line(to_char(to_date('2010-08-09','yyyy-mm-dd')));
end;
--字符函数
begin
dbms_output.put_line(lower('I love CHINA!')); --大写变小写
dbms_output.put_line(upper('You don''t even have a dog!')); --小写变大写
dbms_output.put_line(initcap('poo poo! my sweaty! ')); --每单词首字母大写其余小写
dbms_output.put_line(length('Rocho^_^J')); --求串长
dbms_output.put_line(substr('I love CHINA!',3,4)); --求子串, Oracle中下表从1开始
dbms_output.put_line(instr('I love CHINA!','CHINA')); --求字串的下表
dbms_output.put_line(instr('IN love with CHINA!','IN',5)); --求第5位后的字串的下表
dbms_output.put_line(concat('I love',' you')); --串连接, 不常用. 可用||代替
dbms_output.put_line('I love' || ' you'); --串连接||
dbms_output.put_line(lpad('I love CHINA!',20,'*')); --填充, 15为总长度, 不够补*
dbms_output.put_line(rpad('I love CHINA!',20,'*'));
dbms_output.put_line(trim('C' From 'Carton MovieC')); --去除两边的一个字符
dbms_output.put_line(replace('I love CHINA','CHINA','you')); --替换子串
end;
--数字函数
begin
dbms_output.put_line(round(156.26789,2)); --四舍五入, 2为保留2位小数
dbms_output.put_line(round(156.26789,-2)); --四射五入, -2为保留整数, 从.开始
dbms_output.put_line(trunc(123.4567,3)); --截取.后多少位, 类似上边, 但是不进位
dbms_output.put_line(16 mod 3 );
end;
--日期函数: 中文系统下, 默认日期显示格式为: 日-月-年
--通过alter Session set nls_date_format = 'yyyy-mm-dd'
begin
dbms_output.put_line(to_char(sysdate,'yyyy-mm-dd hh:mi:ss')); --DateTime.Now
dbms_output.put_line(to_char(sysdate,'yyyy')); --年份
dbms_output.put_line(to_char(sysdate,'mm')); --月份
dbms_output.put_line(to_char(sysdate,'dd')); --天书
dbms_output.put_line(to_char(sysdate,'d')); --星期几, 结果需要-1
dbms_output.put_line(to_char(sysdate,'ddd')); --一年中的第几天
dbms_output.put_line(to_char(sysdate,'hh')); --小时
dbms_output.put_line(to_char(sysdate,'hh12')); --12小时制小时
dbms_output.put_line(to_char(sysdate,'hh24')); --24小时制小时
dbms_output.put_line(to_char(sysdate,'mi')); --分
dbms_output.put_line(to_char(sysdate,'ss')); --秒
dbms_output.put_line(to_char(sysdate,'q')); --季度
dbms_output.put_line(to_char(sysdate + 2)); --加减2,得到的前或后两天
dbms_output.put_line(to_char(
months_between(
to_date('2011-08-08','yyyy-mm-dd'),
to_date('2010-11-9','yyyy-mm-dd')
)
)
); --相差几个月
dbms_output.put_line(to_char(
add_months(to_date('2011-08-08','yyyy-mm-dd'),3)
)); --相差几个月
dbms_output.put_line(to_char(
add_months(to_date('2011-08-08','yyyy-mm-dd'),3)
)); --相差几个月
dbms_output.put_line(to_char(
last_day(to_date('2011-08-08','yyyy-mm-dd'))
)); --该月最后一天
dbms_output.put_line(to_number(
to_char(
to_date('2011-8-8','yyyy-mm-dd'),'yyyy')
)
); --日期变数字
end;
select next_day(sysdate,3) from dual --返回下周2的日期, 周的计算从1开始
--###################################################################################
--范式: 1NF: 原子性, 2NF: 单主键, 3NF: 去除传递依赖, BCNF: 决定每个记录的因素都包含关键字, 但不是关键字的子集
--E-R模型(表间关系): 1对1: 任何一个表添加外键; 1对多: 在多的一方添加外键; 多对多: 需要第三个表, 添加前两表的外键
--###################################################################################
--Oracle程序块: declare、begin、exception、end四个关键字, 注意: end后面的";"不能省略, 且打开输出set serveroutput on
--系统变量:
sqlcode --在异常处理中, 返回当前的错误号
sqlerrm --在异常处理中, 返回当前的错误信息
%rowcount --获得sql命令影响的行数
%rowtype --获得表或视图的记录类型
%type --变量类型参考表或视图中字段的类型
%found --用于游标, 表示是否找到数据
%notfound --用于游标, 表示是否没有找到
--自定义变量
declare
v_name nvarchar2(30);
v_email nvarchar2(50) default 'webmaster@google.com';
begin
v_name := '张三';
dbms_output.put_line(v_name);
dbms_output.put_line(v_email);
exception --可省略
when others then
dbms_output.put_line('其他异常');
end;
--条件表达式: 相等为:=, 比较相等为=
declare
v_name nvarchar2(30) := '张三';
v_pass nvarchar2(10) := 'zhangsan';
v_inputname nvarchar2(30);
v_inputpass nvarchar2(10);
begin
v_inputname := '张三';
v_inputpass := 'zhangsan';
if v_inputname <> v_name then
dbms_output.put_line('不存在用户名' || v_inputname);
elsif v_inputpass != v_pass then
dbms_output.put_line('密码错误!');
elsif v_inputname = v_name and v_inputpass = v_pass then
dbms_output.put_line('登陆成功!');
else
dbms_output.put_line('用户名和密码不匹配! ');
end if;
exception
when others then
dbms_output.put_line('系统异常! ');
end;
--循环
declare --输出fibonacci前10项
v_num1 number(5) := 1;
v_num2 number(5) := 1;
v_num3 number(5); --前两个数的和
v_i number(5) := 0; --控制循环次数
begin
dbms_output.put(v_num1); --输出初始的1,1
dbms_output.put(' ' || v_num2);
loop
exit when v_i >= 8; --前两个已有
v_num3 := v_num1 + v_num2;
dbms_output.put(' ' || v_num3);
v_num1 := v_num2;
v_num2 := v_num3;
v_i := v_i + 1;
end loop;
dbms_output.put_line(''); --一定要有put_line才能显示put的信息
--省略exception
end;
--case when
--搜索case when(用于一个范围), Oracle中不支持?
--简单case when(类似swtich, 用于一个定值)
select
case table_name
when 'JOBS' then '工作表'
when 'REGIONS' then '地区表'
when 'DEPARTMENTS' then '部门表'
else '其他表'
end
from user_tables
declare
v_gender number(1) := 0;
begin
case v_gender
when 0 then dbms_output.put_line('男');
when 1 then dbms_output.put_line('女');
else dbms_output.put_line('暂时未知');
end case;
end;
--查询处理: 单行结果可以直接处理, 而多行结果需要用游标处理
--单行结果: 必须有一行结果, 不能是多行也不能是空行
declare
v_title nvarchar2(200);
v_detail T_Event.detail%type; --%type参照表或视图的字段类型
begin
select title,detail into v_title,v_detail
from T_Event
where seqid = 1;
dbms_output.put_line('记事详情: ' || v_title || ' '||v_detail);
end;
--定义记录类型
declare
type T_UserInfo is record(
seqid number(8),
username nvarchar2(30),
create_data date
);
v_row T_UserInfo;
begin
select seqid,username,create_data into v_row
from T_UserInfo
where seqid = 3;
dbms_output.put_line('用户详情: 序号< ' || v_row.seqid || ' > , 用户姓名: < '||v_row.username ||
' > , 用户创建时间: < ' ||v_row.create_data ||' > .');
end;
--参考记录的类型
declare
v_row T_UserInfo%rowtype; --参考原表的记录类型
begin
select seqid,username,create_data into v_row
from T_UserInfo
where seqid = 3;
dbms_output.put_line('用户详情: 序号< ' || v_row.seqid || ' > , 用户姓名: < '||v_row.username ||
' > , 用户创建时间: < ' ||v_row.create_data ||' > .');
end;
--多行结果--->游标: 1. 定义游标cursor 2. 打开游标open 3. 从游标中读取fetch 4. 判断游标状态 5. 关闭游标close
declare
v_row T_UserInfo%rowtype; --参考原表的记录类型
cursor v_cs is select * from T_UserInfo; --1. 定义游标
begin
open v_cs; --2. 打开游标
loop
fetch v_cs into v_row; --3. 从游标读取数据
exit when v_cs%notfound; --4. 判断游标状态
dbms_output.put_line('序号< ' || v_cs%rowcount || ' > ');
dbms_output.put_line('用户姓名: < '||v_row.username || ' > ');
dbms_output.put_line('用户创建时间: < ' ||v_row.create_data ||' > ');
end loop;
close v_cs; --5. 关闭游标
end;
--游标2:
declare
type type_cs is ref cursor; --系统游标
v_cs type_cs;
v_title T_Event.title%type;
v_startdate date;
v_enddate date;
v_detail T_Event.detail%type;
begin
GetNoticesByDateParametersOut(to_date('2010-7-8','yyyy-mm-dd'),v_cs); --掉存储过程
loop
fetch v_cs into v_title, v_startdate, v_enddate, v_detail;
exit when v_cs%notfound;
dbms_output.put_line('记事详情: 标题< ' || v_title || ' > , 开始时间: < '||v_startdate ||
' > , 结束时间: < ' ||v_enddate ||' > , 内容: < ' ||v_detail ||' >. ');
end loop;
close v_cs;
end;
--###################################################################################
--事物: 事物的特性ACID(一致性(Consistency)、原子性(Atomicity)、隔离性(Isolation)、持久性(Durability))
--Oracle中的事物由任意一条DML语句开始, 不需要显示的开始事物
declare
v_username nvarchar2(30);
v_title nvarchar2(200);
v_startdate date;
v_enddate date;
v_detail nvarchar2(500);
v_userid number(8);
begin
v_username := '李四';
v_title := '喝喜酒';
v_startdate := to_date('2010-11-05','yyyy-mm-dd');
v_enddate := to_date('2010-12-05','yyyy-mm-dd');
v_detail := '准时到, 备好红包';
insert into T_UserInfo(seqid,username) values(seq_T_UserInfo.nextval,v_username);
insert into T_Event(seqid,title,startdate,enddate,detail,userid)
values(seq_T_Event.nextval,v_title,v_startdate,v_enddate,v_detail,seq_T_UserInfo.currval);
commit;
exception --异常处理部分如果不写, 则异常将升级到程序的调用环境中处理
when others then
rollback;
dbms_output.put_line('数据写入过程出错, 操作已回滚! ');
end;
--带异常控制的事物
--raise_application_error(-20999,'XXXXX')用于抛出xxxx的自定义异常, 异常号必须在-20000~-20999之间
begin
--raise zero_divide; --即使程序没有错误, 也可以手动抛出异常
insert into T_UserInfo(seqid,username) values(seq_T_UserInfo.nextval,'王五');
insert into T_Event(seqid,title,startdate,enddate,detail,userid)
values(seq_T_Event.nextval,'生日',
to_date('2010-11-05','yyyy-mm-dd'),
to_date('2010-12-05','yyyy-mm-dd'),
'准备蛋糕',
seq_T_UserInfo.currval);
commit;
exception --异常处理部分如果不写, 则异常将升级到程序的调用环境中处理
--Orale内部定义的异常, 资源忙错误号为: -54; sqlcode和sqlerrm用来返回当前错误号和错误信息
when no_data_found then rollback;dbms_output.put_line('错误: 没有找到数据'); --错误号:-1403
when too_many_rows then rollback;dbms_output.put_line('错误: 返回了多行数据! '); --错误号为: -1422
when invalid_cursor then rollback;dbms_output.put_line('错误: 无效的游标 ');
when zero_divide then rollback;dbms_output.put_line('错误: 除0错误 '); --错误号位: -1476
when dup_val_on_index then
rollback;
dbms_output.put_line('错误: 唯一索引不能有重复值! ');
dbms_output.put_line('数据写入过程出错, 操作已回滚! ' || '当前错误号: ' || sqlcode || '当前错误信息: ' || sqlerrm);
when others then
rollback; --手动抛出异常, 程序将中断执行, 因此提前rollback
raise_application_error(-20011,'这是自定义的错误信息! '); --抛出自定义异常
end;
--###################################################################################
--索引: 列中包含大范围值、列中包含大量null、经常被用户查询的where或join的连接条件、表中数据多, 但常用的行少于2%-4%
create index lower_Employees_Last_name_Idx on employees(lower(last_name)) --为提高查询效率, 先转一下小写
select * from user_indexes --查询索引
select * from user_ind_columns --索引中列的数据字典
--###################################################################################
--存储过程(Stored Procedure): 只需要定义参数的类型, 而不能指定参数的宽度,in、out、in out, SP用来存储程序块
--带参数的
create or replace procedure SP_ShowFibonacci(
p_num in number
)
is
v_num1 number(5) := 1;
v_num2 number(5) := 1;
v_num3 number(5) := 0;
v_i number(5) := 0;
begin
dbms_output.put(v_num1 || ' ');
dbms_output.put(v_num2 || ' ');
loop
exit when v_i >= p_num - 2;
v_num3 := v_num1 + v_num2;
dbms_output.put(v_num3 || ' ');
v_num1 := v_num2;
v_num2 := v_num3;
v_i := v_i + 1;
end loop;
dbms_output.put_line(''); --显示结果
end Sp_ShowFibonacci;
--调用: sqlplus中, exec ShowFibonacci(15);
begin
ShowFibonacci(15); --在程序块中调用存储过程不需要exec
end;
--带输入参数和普通输出参数, in表示传入参数, out表示输出参数, returning用于返回刚刚插入的记录
create or replace procedure SP_InsertAndReturnPKFromT_Event(
p_pkid out number, --输出参数
p_title in nvarchar2,
p_startdate in date,
p_enddate date, --默认就是in
p_detail in nvarchar2,
p_userid in number
)
is
--v_pkid number(8);
begin
--v_pkid := seq_t_event.curral; --暂存currval
insert into T_Event(seqid,title,startdate,enddate,detail,userid)
values(seq_t_event.nextval,p_title,p_startdate,p_enddate,p_detail,p_userid)
returning seqid into p_pkid; --注意: returning是insert的子句, 用于返回刚插入的记录, 所以前面无分号
--p_pkid := seq_t_event.currval; --这种返回方法, 需要在插入前缓存currval
commit;
exception
when others then
rollback;
end InsertAndReturnPKFromT_Event;
--调用: 带输出参数的存储过程在Sqlplus中调用也需要写程序块
--程序块调用, 不需要exec
declare
v_pkid number(8);
begin
SP_InsertAndReturnPKFromT_Event(v_pkid,'吃饭',to_date('2010-11-07','yyyy-mm-dd'),
to_date('2010-12-05','yyyy-mm-dd'),'带红包',1);
dbms_output.put_line(v_pkid);
end;
--带输入参数和系统引用输出游标
create or replace procedure SP_GetEVentByDate(
p_date in date,
p_userid in number,
p_cs out sys_refcursor
)
is
v_cs sys_refcursor; --1. 定义游标
begin
open v_cs --2. 打开游标
for
select title,startdate,enddate,detail,userid
from T_Event
where to_date(to_char(startdate,'yyyy-mm-dd'),'yyyy-mm-dd') = p_date and userid = p_userid;
--startdate要去掉时间, 才能查到多条记录. to_char之后再to_date即可
--3. 将查询结果以游标输出
p_cs := v_cs;
end GetEventByDate;
--调用
declare
v_cs sys_refcursor;
v_title nvarchar2(200);
v_startdate date;
v_enddate date;
v_detail nvarchar2(500);
v_userid number(8);
begin
--程序块使用游标, 不需要加exec
SP_GetEVentByDate(to_date('2010-11-05','yyyy-mm-dd'),1,v_cs);
--使用输出游标, 也不需要打开游标
loop
fetch v_cs into v_title,v_startdate,v_enddate,v_detail,v_userid;
exit when v_cs%notfound;
dbms_output.put_line(v_title || v_startdate || v_enddate || v_detail || v_userid);
end loop;
close v_cs; --关闭游标
end;
--通过存储过程插入数据
create or replace procedure SP_NewNoticeItem(
p_date in date,
p_start in date,
p_end in date,
p_title in NoticeItem.title%type,
p_content in NoticeItem.content%type
)
is
v_count calender.itemcount%type;
v_calender_dateid calender.dateid%type;
begin
--判断calender中是否有相应的记录
select nvl(sum(itemcount),0), sum(dateid) into v_count, v_calender_dateid
from calender
where dateitem = p_date;
--如果有, 则更新数量, 这里同样也需要暂存dateid, 以便在noticeitem表中进行添加
if v_count >0 then
update calender set itemcount = v_count + 1 --update set之后是采用=号
where dateitem = p_date;
else
--如果无, 则增加新纪录
--v_calender_dateid := seq_calender.nextval; --不能直接使用sequence, 因多人访问, 需要用局部变量暂存sequence
select seq_calender.nextval into v_calender_dateid from dual; --以上表达式的另外一种写法
insert into calender(dateid,dateitem,itemcount)
--values(seq_calender.nextval, p_date, 1);
values(v_calender_dateid,p_date, 1);
end if;
-- 在NoticeItem表中增加活动的内容
insert into NoticeItem(itemid, dateid, start_time, end_time, title, content)
--values(seq_noticeitem.curval, seq_calender.curval) --因为多人访问, 所以seq_calender.NextVal可能被改变, 需暂存
values(seq_noticeitem.nextval, v_calender_dateid, p_start, p_end, p_title, p_content);
commit;
--如果中间有异常, 则rollback
exception
when others then
rollback;
end SP_NewNoticeItem;
--###################################################################################
--函数: 与存储过程相比, 函数必须有返回类型, 内部应只对数据进行运算, 避免在函数中处理记录--用来存储程序块
create or replace function fn_truncdate(
p_date date
)
return date
is
result date;
begin
result := to_date(to_char(p_date,'yyyy-mm-dd'),'yyyy-mm-dd');
return result;
exception
when others then
dbms_output.put_line('截取日期出现错误');
end;
--调用
select fn_truncdate(to_date('1985-11-11 8:30','yyyy-mm-dd hh-mi')) from dual
--###################################################################################
--触发器: 分为基于表(before,after)和基于视图(instead of). :new表示新纪录, :old表示旧记录.
-- 还可以通过deleting、inserting和updating获得引起触发器的动作
--视图存储的是Sql语句, 所以通常只对表进行DML操作的触发器
create or replace trigger tg_noticeitem
after delete on noticeitem
for each row
declare
v_count calender.itemcount%type;
begin
--触发器中的隐士参数(:new 代表操作之后的记录 :old 代表操作之前的记录)
--(:old.dateid)表示noticeitem中的外键
--读取calender表中的活动的数量itemcount
select itemcount into v_count
from calender
where dateid = :old.dateid;
if v_count > 1 then
update calender
set itemcount = itemcount -1
where dateid = :old.dateid;
else--注意elsif的写法
delete from calender
where dateid = :old.dateid;
end if;
end tg_noticeitem;
--创建监视表
drop table T_Monitor
create table T_Monitor(
table_name nvarchar2(30),
constraint pk_T_monitor primary key(table_name),
count number(8),
create_date date default(sysdate)
)
insert into T_Monitor(table_name,count) values('T_EVENT',0)
commit
create or replace trigger tg_monitor --触发器没有参数
after insert or delete or update on T_EVENT
--for each row --默认为statement level表示语句级, 表示一条语句执行一次, 而each row表示每行
declare
begin
if deleting then
dbms_output.put_line('删除操作! ');
elsif inserting then
dbms_output.put_line('插入操作! ');
elsif updating then
dbms_output.put_line('更新操作! ');
end if;
update T_Monitor set count = count + 1
where table_name = 'T_EVENT';
end tg_monitor;