ORACLE
|-入门语句
|-数据库连接
|-普通用户连接:Conn scott/tiger
|-超级管理员连接:Conn sys/sys as sysdba
|-断开连接:Disconnect
|-SQL操作
|-保存SQL文件:Save c:\1.txt
|-编辑SQL语句:Ed c:\1.txt
|-运行SQL语句:@ c:\1.txt
|-显示表结构:Desc tableName;
|-查看用户下的所有对象: Select * from tab;
|-系统表操作
|-查询指定名称表信息:select owner, object_name, status from dba_objects where object_name like '%DUAL%'
|-单行函数
|-字符函数
|-Upper
|-Lower
|-Initcap
|-将字符串首字母变成大写
|-concat
|-concat('a', 'b')= 'a'||'b' --> 'ab'
|-substr
|-substr( string, start_position, [ length ] )
|-replace
|-replace('Abc', 'a', 'A') --> 'abc'
|-instr
|-instr(源串,目标串[,开始位置[,第几次出现]])
|-lpad/ rpad
|-lpad(源串,数量,数量不足的时候填充的字符串);
|-select lpad('yao', 10, 'fuck') from dual; --> 'fuckfucyao'
|-trim
|-数值函数
|-Round
|-ROUND(指定数值, 指定位数)
|-例:select round(412, -2), round(412.313, 2) from dual; --> 400, 412.31
|-Mod
|-Mod(n1, n2) --> n1%n2
|-Trunc
|-意为截断,不进行四舍五入操作
|-日期型
|-select trun(sysdate, 'mm' from dual; --> 01-7月 -12
|-select trun(sysdate, 'dd' from dual; --> 23-7月 -12
|-数值型
|-select trunc(89.986, 2) from dual; --> 89.98
|-日期函数
|-Months_between
|-select sysdate, to_date('20120612', 'yyyymmdd'), months_between(sysdate, to_date('20120612', 'yyyymmdd')) from dual; --> 1.38223118
|-Add_months
|-select sysdate, add_months(sysdate, 1) from dual; --> 2012-07-23, 2012-08-23
|-Next_day
|-下一个指定星期:select sysdate, next_day(sysdate, '星期四') from dual; --> 2012-07-23 星期一, 2012-07-26 星期四
|-last_day
|-该月最后一天:select last_day(sysdate) from dual; --> 2012-07-31
|-转换函数
|-to_char
|-to_char(sysdate, 'yyyy') --> 2012
|-to_char(sysdate, 'fmyyyy-mm-dd') --> 2012-07-23
|-to_char(111.1, 'L999, 999, 999') --> ¥999
|-to_number
|-select to_number('13')+ to_number('14') from dual;
|-to_date
|-select to_date('20120723', 'yyyymmdd') from dual;
|-通用函数
|-NVL
|-空值时设置为默认值:select nvl(null, 0), nvl(111, 0) from dual; --> 0, 111;
|-NULLIF
|-相等返回NULL,否则返回第一个值:select nullif(0,0), nullif(11,12) from dual; --> null, 11;
|-NVL2
|-值1为空返回值3,否则返回值2:select nvl2(null,1,2), nvl2(1,1,2) from dual; --> 2, 1
|-CLALESCE
|-返回第一个非空值,参数为同类型(!!)无限数量:select coalesce(null, null, 1, null, 2) from dual;
|-CASE
|-select empno, ename, case deptno when 1 then '财务部' when 2 then '外交部' when 3 then '开发部' else 'FBI' end as 部门 from emp;
|-DECODE
|-与CASE一般用途:select empno, ename,decode(deptno, 1,'财务部', 2, '外交部', 3, '开发部', 'FBI') as 部门 from emp;
|-多表查询
|-笛卡尔集
|-select * from emp, dept;
|-等值连接
|-select dname, ename, hiredate from emp, dept where emp.deptno= dept.deptno;
|-非等值连接
|-笛卡尔集的基础上进行条件判断:select ename, empno, grade, sal, losal, hisal from emp, salgrade where sal between losal and hisal;
|-自连接
|-select e.ename, m.empno from emp e, emp m where e.mgr= e.empno;
|-左外联接
|-select s.sname, t.tname from student s, teacher t where s.ssex= t.tsex(+)
|-select s.sname, t.tname from student s left join teacher t on s.ssex= t.tsex
|-右外联接
|-满外联接
|-select s.sname, t.tname from student s full outer join teacher t on s.ssex= t.tsex
|-集合操作
|-UNION
|-并集,显示所有,但重复项只显示一次
|-UNION ALL
|-并集,显示所有,包括重复项
|-INTERSECT
|-交集,只显示重复项
|-MINUS
|-差集,只显示对没有的,与顺序有关
|-子查询
|-单行子查询
|-select * from student where sage >(select sage from student where sid= 80308100);
|-子查询结果为空时无返回结果
|-子查询返回多行时报错
|-多行子查询
|- SELECT * FROM TABLEA WHERE FLD > ALL(SELECT FLD FROM TABLEA) == SELECT * FROM TABLEA WHERE FLD > (SELECT MAX(FLD) FROM TABLEA)
|- SELECT * FROM TABLEA WHERE FLD > ANY(SELECT FLD FROM TABLEA) == SELECT * FROM TABLEA WHERE FLD > (SELECT MIN(FLD) FROM TABLEA)
|- SELECT * FROM TABLEA WHERE FLD = ANY(SELECT FLD FROM TABLEA) == SELECT * FROM TABLEA WHERE FLD IN (SELECT FLD FROM TABLEA)
|-分页查询
|-select * from (select rownum no, e.* from (select * from emp order by sal desc) e where rownum<= 5) where no>= 3;
|-EXISTS
|-select * from student s where exists (select null from teacher t where t.tage> 2* s.sage);
|-注意事项
|-子查询记录少,主查询表大且有索引时用IN,反之用EXISTS
|-高级查询
|-随机返回指定数量的记录
|-SELECT * FROM (SELECT * FROM student ORDER BY dbms_random.value()) WHERE ROWNUM<= 2;
|-排序的时候进行空值优先顺序
|-SELECT * FROM student ORDER BY sname NULLS FIRST;
|-为行指定行标记,不同于行序ROWNUM
|-SELECT * FROM (SELECT row_number() over (ORDER BY sname) rn, sname FROM student) s WHERE MOD(rn, 2)= 1;
|-同时查询最大最小值
|-SELECT MAX(sage) over(), MIN(sage) over() FROM student;
|-连续求和
|-SELECT sname, sage, SUM(sage) over(), SUM(sage) over(ORDER BY sname) FROM student;
|-SUM(sage) over()= SUM(sage),但可用于非聚合语句中
|-SUM(sage) over(ORDER BY sname),在sname的层次上逐个添加
|- SNAME SAGE SUM(SAGE)OVER() SUM(SAGE)OVER(ORDERBYSNAME)
1 潘巧容 23 57 23
2 王老吉 10 57 33
3 姚清居 24 57 57
4 57 57
|-分组求和
|-SELECT sname, ssex, sage, SUM(sage) over(PARTITION BY ssex ORDER BY sname) FROM student;
|- SNAME SSEX SAGE SUM(SAGE)OVER(PARTITIONBYSSEXO
1 test 男 99 99
2 姚清居 男 24 123
3 female 女 33 33
4 潘巧容 女 23 56
5 王老吉 中性 10 10
6 88 88
|-得到上行记录和下行记录
|-SELECT
sname, sage,
lead(sage) over(ORDER BY sage) nextAge,
lag(sage) over(ORDER BY sage) frontAge
FROM student;
|-根据子串分组
|-SELECT to_char(tmp_date, 'yyyy'), AVG(tmp_id)
FROM temp
GROUP BY to_char(tmp_date, 'yyyy');
|-确定一年的天数
|-SELECT add_months(trunc(SYSDATE, 'y'), 12) - trunc(SYSDATE, 'y') FROM dual;
|-查询每个性别下最年轻的前两位的信息
|-SELECT * FROM (
SELECT sname, ssex, sage, row_number() over(PARTITION BY ssex ORDER BY sage) rn
FROM student
)
WHERE rn< 3;
|-SELECT sname, ssex, sage
FROM student s1
WHERE (
SELECT COUNT(1)
FROM student s2
WHERE s1.ssex= s2.ssex AND s1.sname!= s2.sname AND s2.sage< s1.sage
)< 2
ORDER BY ssex, sage;
|-数据字典
|-查询用户权限表
|-SELECT * FROM All_Tables WHERE owner= 'YQJ';
|-查看指定用户拥有的指定表单的所有字段完整信息
|-SELECT * FROM all_tab_columns WHERE table_name= 'STUDENT' AND owner= 'YQJ';
|-查询表索引
|-SELECT * FROM sys.All_Ind_Columns WHERE table_name= 'STUDENT';
|-查询表约束
|-SELECT * FROM all_constraints WHERE table_name= upper('student');
|-查询Oracle中描述数据字典视图
|-SELECT table_name, comments FROM DICTIONARY WHERE table_name LIKE '%TABLE%';
|-Oracle体系结构(DBA)
|-数据库
|-一系列物理文件(数据文件,控制文件,重做日志文件,联机日志等)的集合与对应的逻辑结构(表空间、段、区、块等)
|-数据库实例
|-内存结构
|-SGA
|-PGA
|-后台进程
|-DDL- 改变表结构
|-建表
|-自定义表结构
CREATE TABLE person(
pID NUMBER(10),
pName VARCHAR2(30),
pSex VARCHAR2(10)
)TABLESPACE yqj; --不写默认创建在当前用户的表空间上
|-在已有表基础上进行结构和数据搭建
CREATE TABLE employ
AS SELECT 0 AS sel, person.* FROM person;*
|-新增字段
|-ALTER TABLE EMPLOY ADD eage NUMBER(5);
|-修改字段属性
|-ALTER TABLE employ MODIFY eage NUMBER(10);
|-修改字段名称
|-ALTER TABLE employ RENAME COLUMN psex TO esex;
|-删除字段
|-ALTER TABLE employ DROP COLUMN test;
|-清空表数据
|-TRUNCATE TABLE employ;
|-表重命名
|-RENAME employ TO zhiyuan;
|-DML- 改变数据结构
|-插入
|-INSERT INTO aaa(sid, sname, ssex, sage, saddress)
SELECT sid, sname, ssex, sage, saddress FROM student WHERE ssex= '中性'
|-更新
|-UPDATE aaa
SET(sname, saddress)=
(SELECT sname||'2', saddress||'2' FROM aaa WHERE sid= 80308101)
WHERE sid= 80308100
|-删除
|-DELETE FROM aaa WHERE sid= 80308100;
|-有更没插
|-MERGE INTO aaa
USING student --这个标注了范围
ON(aaa.sid= student.sid)
WHEN MATCHED THEN
UPDATE SET sname= student.sname, ssex= student.ssex, saddress= student.saddress
WHEN NOT MATCHED THEN
INSERT(sid, sname, ssex, sage, saddress) VALUES(student.sid, student.sname, student.ssex, student.sage, student.saddress)
;
|-约束
|-例
|-CREATE TABLE constraintExamp(
cID NUMBER PRIMARY KEY,
cName VARCHAR(30) NOT NULL,
cTel VARCHAR2(50) UNIQUE,
cAge NUMBER CHECK(cAge BETWEEN 0 AND 150),
cCountryID NUMBER REFERENCES country(cCountryID) ON DELETE CASCADE
);
|-非空约束
|-NOT NULL
|-限制该项不为置空
|-主键约束
|-PRIMARY KEY
|-不能重复,不能为空
|-唯一约束
|-UNIQUE
|-值不能重复,空值除外
|-条件约束
|-CHECK
|-插入数据必须满足特定条件
|-外键约束
|-指定该项值取自指定表的列值kwkw
|-cCountryID NUMBER REFERENCES country(cCountryID)
|-CONSTRAINT constraintExamp_cCountryID_fk FOREIGH KEY(cCountryID) REFERENCES COUNTRY(cCountryID)
|-级联删除
|-主表信息删除后,自动进行关联表的信息清除
|-ON DELETE CASCADE
|-增加约束
|-ALTER TABLE CONSTRAINTEXAMP ADD CONSTRAINT constraintExamp_cID_pk PRIMARY KEY(cid);
ALTER TABLE CONSTRAINTEXAMP ADD CONSTRAINT constraintExamp_cTel_uk UNIQUE(cTel);
ALTER TABLE CONSTRAINTEXAMP ADD CONSTRAINT constraintExamp_cAge_ck CHECK(cage BETWEEN 0 AND 150);
ALTER TABLE CONSTRAINTEXAMP ADD CONSTRAINT country_constraintExamp_cCountryID_fk FOREIGN KEY(cCountryID) REFERENCES country(cCountryID) ON DELETE CASCADE;
|-删除约束
|-ALTER TABLE CONSTRAINTEXAMP DROP CONSTRAINT constraintExamp_cID_pk;
|-启用约束
|-ALTER TABLE CONSTRAINTEXAMP ENABLE CONSTRAINT constraintExamp_cID_pk;
|-禁用约束
|-ALTER TABLE CONSTRAINTEXAMP DISABLE CONSTRAINT constraintExamp_cID_pk;
|-视图
|-概念:封装了各种复杂查询的语句
|-创建视图
|-CREATE VIEW 视图名称(字段) AS 子查询
|-CREATE OR REPLACE VIEW maleStudent (sid, sname, ssex, sage, saddress)
AS
SELECT sid, sname, ssex, sage, saddress
FROM student
WHERE ssex= '男'
WITH CHECK OPTION CONSTRAINT maleStudent_ck;
--WITH READ ONLY;
|-更新视图
|-UPDATE maleStudent SET ssex= '';
|-注意会联动更新原表记录
|-保护视图的创建规则
|-保护WHERE语句中的字段不被修改
|-WITH CHECK OPTION CONSTRAINT maleStudent_ck
|-只读
|-设置任意字段都不可更改,视图为只读
|-WITH READ ONLY
|-查看视图
|-SELECT * FROM maleStudent;
|-索引
|-定义
|-用于提升查询效率的数据库对象
|-通过快速定位数据的方法来减少磁盘I/O操作
|-索引信息与表独立存放
|-Oracle数据库自动使用和维护索引
|-分类
|-唯一性索引
|-非唯一性索引
|-创建方式
|-自动创建
|-在定义主键和唯一键时系统自动在相应字段上创建唯一性索引
|-手动创建
|-用户选择在其它列上创建非唯一索引,以加速查询速度
|-查询方式
|-查询现有的索引信息:SELECT * FROM user_indexes;
|-查询索引建立在哪些字段上:SELECT * FROM user_ind_columns;
|-优缺点
|-优点
|-极大加快数据的检索速度
|-创建唯一性索引,保证数据库中第一行数据的唯一性
|-加速表和表之间的连接
|-使用分组和排序子句进行检索时,明显减少查询速度
|-缺点
|-索引需要占用物理空间
|-当对表中数据进行增删改时,索引亦需动态维护,降低数据维护速度
|-创建原则
|-select占多的表上
|-where语句中出现频率最高的列
|-小于5M的表,最好不要使用索引查询,表越小越适合用全表扫描
|-使用原则
|-复合索引按f1,f2,f3次序建立,where语句中若无f2= '1',会因f2不是索引第一个字段而无法进行索引查询
|-索引查询避免任何形式计算,并将操作移到等号右边
|-如下操作会显式阻止Oracle使用索引:is(not) null, not in, !=, like, numeric_col+ 0, date_col+ 0; char_col||'', to_char, to_number, to_date;
|-创建索引
|-CREATE INDEX student_index ON student(sid, sname);
|-注:建立索引时,组合的顺序关系非常重要
|-索引存储
|-索引和表独立存在,建议两种不要放置于同一表空间,从而避免IO冲突。
|-删除索引
|-DROP INDEX student_index ;
|-管理索引
|-先插入数据后再创建索引
|-为索引指定表空间
|-SQL优化
|-实质
|-在结果正确的前提下,
用优化器可识别的语句,
充分利用索引,
执行过程中访问尽量少的数据块,减少表扫描的I/O次数,
尽量避免全表扫描和其它额外开销。
|-优化器
|-RBO- rule-based-opimizer
|-根据自己内部设定的规则进行
|-CBO- cost-based-opimizer
|-建议使用,更多地根据表及索引的状态信息来选择计划
|-尽量少用IN,而用EXISTS代替
|-主大子小用IN,主小子大用EXISTS
|-用NOT EXISTS或外连接代替NOT IN
|-因为NOT IN不能应用表的索引
|-尽量不用<> 或者!= 操作符
|-不等于操作符永远不会用到索引,对它的处理只会产生全表扫描
|-设计表的时候,将索引列设置为NOT NULL
|-判断字段是否为空是不会应用到索引的,因为B树索引是不索引空值的
|-尽量不用能配符"%"或 "_"做为查询字符串的第一个字符
|-出现如上的情况时,索引是不会被使用的
|-WHERE子句中避免在索引列上使用计算
|-如果索引并非基于函数的,那么当在Where子句中对索引列使用函数时,索引不再志作用
|-用">="替代">"
|-A>2时,ORACLE会先找出为2的记录索引再进行比较,而A>=3时ORACLE则直接找=3的记录索引
|-利用SGA共享池,避开parse阶段
|-不同区域出现的相同SQL语句要保证查询字符完全相同,建议经常使用的用常量代替,以利用SGA共享池,避开parse阶段,防止相同的sql语句被多次分析
|-其中存储过程就是提高效率的一种有效方法
|-WHERE后面的条件顺序要求
|-表连接语句写在最前面,可以过滤掉最大数量记录的条件居后
|-使用表的别名,并将之作为每列的前缀
|-连接多表时,使用表别名并作为列前缀,可以减少解析时间
|-进行显式或隐式运算的字段不能进行索引
|-所以与索引列进行比较的时候,只进行结果比较,不对索引列进行数值计算
|-用UNION ALL代替UNION
|-UNION会进行SORT UNIQUE,即数据唯一性校验,但实质连接的一般不会出现重复记录,所以可以采用UNION ALL,不排除重复记录行,效率可以更高
|-改变ORACLE的SGA的大小
|-定义
|-数据库的系统全局区
|-组成
|-共享池+ 数据缓冲区+ 日志缓冲区
|-共享池
|-共享SQL区
|-专门存放用户SQL命令,使用最近最少使用等优先级算法来更新覆盖
|-数据字典缓冲区
|-存放数据库的动态信息
|-DBA可查看这些内存的命中率以从数据库的角度对数据库性能调优
|-查看共享区SQL的重用率:SELECT (SUM(pins- reloads))/ SUM(pins) AS "Lib Cache" FROM v$librarycache;
|-低于90%时建议增加共享池大小
|-查询数据字典缓冲区的命中率:SELECT (SUM(gets- getmisses- USAGE- fixed)/ SUM(gets)) AS "Row Cache" FROM v$rowcache;
|-同样最好在90%以上,否则建议增加共享池大小
|-数据缓冲区
|-存放SQL运行结果到抓取到data block
|-查看数据库缓冲区的使用情况SELECT NAME, VALUE FROM v$sysstat WHERE NAME IN('db block gets', 'consistent gets', 'physical reads');
|-查看数据缓冲区的命中率:SELECT 1- (SUM(CASE WHEN NAME= 'physical reads' THEN VALUE ELSE 0 END) /(SUM(CASE WHEN NAME= 'consistent gets' THEN VALUE ELSE 0 END)+ SUM(CASE WHEN NAME= 'db block gets' THEN VALUE ELSE 0 END))) FROM v$sysstat
|-最好在90%以上,否则建议增加数据缓冲区大小
|-日志缓冲区
|-存放数据库生成的日志
|-查看日志缓冲区的使用情况:SELECT NAME, VALUE FROM v$sysstat WHERE NAME IN ('redo entries', 'redo log space requests');
|-计算日志缓冲区的申请失败率:SELECT SUM(CASE WHEN NAME= 'redo log space requests' THEN VALUE ELSE 0 END)/ SUM(CASE WHEN NAME= 'redo entries' THEN VALUE ELSE 0 END) FROM v$sysstat;
|-失败率应接近0,否则说明日志缓冲区太小,需要增加。
|-序列、同义词
|-序列
|-创建序列
|-CREATE SEQUENCE temp_sq
START WITH 1
INCREMENT BY 1
ORDER
CACHE 20 --可以关闭NOCACHE,但进行内存缓冲对性能有所提高
NOCYCLE; --确保该序列用于多表的情况下,ID是唯一的 --CYCLE MAXVALUE 10,即到10后重新从1开始
|-读取数值
|-SELECT temp_sq.nextval FROM dual;
SELECT temp_sq.currval FROM dual; --必须调用nextval后才能使用currval
|-改变增量
|-注:不能改变当前值,只能改变增量:ALTER SEQUENCE temp_sq INCREMENT BY 3;
|-实现表ID自增
|-CREATE SEQUENCE temp_sq
START WITH 1
INCREMENT BY 1
CACHE 20
NOCYCLE;
CREATE OR REPLACE TRIGGER trg_temp_insert
BEFORE INSERT
ON temp
FOR EACH ROW
BEGIN
SELECT temp_sq.nextval INTO :new.tmp_id FROM dual;
END;
|-同义词
|-概念
|-方便操作不同用户下的对象
|-使两个应用程序使用不同的名字指向同一张表
|-使不同用户指向同一张表
|-创建同义词
|-CREATE PUBLIC SYNONYM student FOR sys.student;
|-删除同义词
|-DROP PUBLIC SYNONYM student;
|-PL SQL
|-PL/SQL块
|-DECLARE
eNO student.sid%TYPE; --指定表中对应列类型
stu student%ROWTYPE; --表结构的复合类型
eName VARCHAR2(30); --此处只是展示使用方法,并无实际用途
BEGIN
eNO:= &请输入学号信息; --进行数据录入,其中&后面为界面显示名称
SELECT * INTO stu FROM student WHERE sid= eNO;
DBMS_OUTPUT.put_line('编号为'||eNO||'雇员的姓名为:'||stu.sname); --使用方法与表一致
EXCEPTION
WHEN no_data_found THEN
DBMS_OUTPUT.put_line('没有此雇员信息'); --对应情况下的信息显示
WHEN ZERO_DIVIDE THEN
DBMS_OUTPUT.put_line('error');
END;
|-LOOP
|-DECLARE
i NUMBER;
BEGIN
i:= 1; --给定初始值
LOOP
DBMS_OUTPUT.put_line(i); --循环执行语句
EXIT WHEN i>= 10;
i:= i+ 1; --条件变更语句
END LOOP;
END;
|-WHILE
|-DECLARE
i NUMBER;
BEGIN
i:= 1; --给定初始值
WHILE(i<= 10) LOOP
DBMS_OUTPUT.put_line(i);
i:= i+ 1;
END LOOP;
END;
|-FOR
|-DECLARE
i NUMBER;
BEGIN
FOR i IN 1..10 LOOP
DBMS_OUTPUT.put_line(i);
END LOOP;
END;
|-IF
|-DECLARE
i NUMBER;
BEGIN
i:= 1;
IF i< 10 THEN
DBMS_OUTPUT.put_line(i||'< 10');
END IF;
END;
|-IF ESLE
|-DECLARE
i NUMBER;
BEGIN
i:= 11;
IF i< 10 THEN
DBMS_OUTPUT.put_line(i||'< 10');
ELSE
DBMS_OUTPUT.put_line(i||'>= 10');
END IF;
END;
|-IF ESLIF ELSE
|-DECLARE
i NUMBER;
BEGIN
i:= 11;
IF i< 10 THEN
DBMS_OUTPUT.put_line(i||'< 10');
ELSIF i> 20 THEN
DBMS_OUTPUT.put_line(i||'> 20');
ELSE
DBMS_OUTPUT.put_line('10< '||i||'< 20');
END IF;
END;
|-GOTO
|-DECLARE
i NUMBER;
BEGIN
i:= 11;
IF i< 10 THEN
GOTO to1;
ELSIF i> 20 THEN
GOTO to2;
ELSE
GOTO to3;
END IF;
<<to1>>
DBMS_OUTPUT.put_line(i||'< 10');
<<to2>>
DBMS_OUTPUT.put_line(i||'> 20');
<<to3>>
DBMS_OUTPUT.put_line('10< '||i||'< 20');
END;
|-游标、函数
|-游标
|-实质
|-PL/SQL控制结构,便于对表的行数据逐条进行处理,但它并非数据库对象,只存留在内存中
|-操作步骤
|-声明游标
|-打开游标
|-取出结果,注结果取出的为一行数据
|-关闭游标
|-例子
|-FOR循环操作游标,游标只作为结果集
|-DECLARE
CURSOR tmpCur IS SELECT * FROM student WHERE ssex= '男';
stu student%ROWTYPE;
sID NUMBER;
BEGIN
FOR stu IN tmpCur LOOP
sID:= tmpCur%ROWCOUNT;
DBMS_OUTPUT.put_line(sID||'ID= '||stu.sID||' ,sName= '||stu.sName);
END LOOP;
END;
|-遍历游标,进行数据处理
|-DECLARE
CURSOR tmpCur IS SELECT * FROM student WHERE ssex= '男'; --进行游标声明
stu student%ROWTYPE;
sID NUMBER;
BEGIN
IF tmpCur%ISOPEN THEN --打开游标前先进行确认游标是否已经打开
NULL;
ELSE
OPEN tmpCur;
END IF;
FETCH tmpCur INTO stu; --游标数据封装至变量中
WHILE(tmpCur%FOUND) LOOP --判断该行是否有数据
DBMS_OUTPUT.put_line('ID= '||stu.sID||' ,sName= '||stu.sName);
FETCH tmpCur INTO stu;
END LOOP;
END;
|-函数
|-创建
|-CREATE OR REPLACE FUNCTION test(sIn student.sID%TYPE)
RETURN student.sName%TYPE
AS
sOut student.sName%TYPE;
BEGIN
SELECT s.sname INTO sOut FROM student s WHERE s.sID= sIn;
RETURN sOut;
END;
|-使用
|-SELECT test(80308078) FROM dual;
|-存储过程
|-创建存储过程
|-CREATE OR REPLACE PROCEDURE pro(
sNO IN student.sid%TYPE, --IN表示只录入
sXM OUT student.sname%TYPE --OUT表示只作为数据输出之用
)
AS
BEGIN
SELECT sName INTO sXM FROM student WHERE sid= sNO;
END;
|-执行
|-DECLARE
sXM student.sName%TYPE;
BEGIN
pro(80308078, sXM);
DBMS_OUTPUT.put_line(sXM);
END;
|-删除存储过程
|-DROP PROCEDURE pro;
|-触发器
|-实质
|-存放数据库,并被隐含执行的存储过程。
|-创建(语句& 行触发器)
|-CREATE OR REPLACE TRIGGER tr_student_dml
BEFORE INSERT OR UPDATE OR DELETE
ON student
BEGIN IF to_char(SYSDATE, 'dy') IN ('星期六', '星期天') THEN
CASE
WHEN inserting THEN
raise_application_error(-20001, '对不起,不能在指定日期插入档案信息'); --用于返回自定义错误信息,数值支持-20000~-20999
WHEN updating THEN
raise_application_error(-20001, '对不起,不能在指定日期更新档案信息');
WHEN deleting THEN
raise_application_error(-20001, '对不起,不能在指定日期删除档案信息');
END CASE;
END IF;
END;
--建立关于student表的增、删、改次记录
CREATE TABLE count_table(
cName VARCHAR2(30) NOT NULL,
bAdd NUMBER(1) DEFAULT 0,
bDelete NUMBER(1) DEFAULT 0,
bUpdate NUMBER(1) DEFAULT 0,
dChangeDate DATE DEFAULT SYSDATE
);
CREATE OR REPLACE TRIGGER tr_count_student
AFTER INSERT OR UPDATE OR DELETE
ON student
FOR EACH ROW --针对一语句影响多条的情况,针对每条进行处理 --行触发,不加则行语句触发
BEGIN --基于对student表的触发,则代码不能从触发器所对应的基表中读取数据
CASE
WHEN inserting THEN
INSERT INTO count_table VALUES(upper('student'), 1, 0, 0, SYSDATE);
DBMS_OUTPUT.PUT_LINE(:new.sName); --:new表示当前记录,:old表示还旧记录
WHEN updating THEN
INSERT INTO count_table VALUES(upper('student'), 0, 1, 0, SYSDATE);
WHEN deleting THEN
INSERT INTO count_table VALUES(upper('student'), 0, 0, 1, SYSDATE);
END CASE;
END;
|-测试
|-DECLARE
no_babies_allowed EXCEPTION;
PRAGMA EXCEPTION_INIT(no_babies_allowed, -20001); --预编译将名称与用于触发器中的错误号码关联起来
BEGIN
INSERT INTO student VALUES (1, 'yao', '男', 1, '');
EXCEPTION
WHEN no_babies_allowed THEN --SQLERRM 将传递给内置过程 RAISE_APPLICATION_ERROR 的消息返回
DBMS_OUTPUT.PUT_LINE(SQLERRM); --返回指定代码错误
END;
|-作用
|-控制数据安全:在非工作时间不能对表进行操作
|-实现数据统计
|-实现数据的完整性,进行数据的限制
|-实现参照完整性:比如级联更新
|-系统事件触发器
|-基于Oracle系统事件(LOGON/STARTUP)所建立的触发器,提供跟踪系统或数据库变化的机制。
|-常用事件属性函数
|-ora_client_ip_address:返回客户端IP地址
|-ora_database_name:返回当前数据库名
|-ora_des_encrypted_password:返回DEX加密后的用户口令
|-ora_dict_obj_name:返回DDL操作中所对应的数据库对象名
|-ora_dict_obj_name_list(name_list OUT, ora_name_list_t):事件中被修改的对象名列表
|-ora_dict_obj_type:返回DDL操作所对应的数据库对象类型
|-ora_grantee(user_list OUT ora_name_list_t):返回授权事件的授权者
|-ora_instance_num:返回例程号
|-ora_is_alter_column(column_name IN VARCHAR2):检测特定列是否被修改
|-ora_is_creating_nested_table:检测是否正在建立嵌套表
|-ora_is_drop_column(column_name IN VARCHAR2):检测特定列是否被删除
|-ora_is_servererror(error_number):检测是否返回特定Oracle错误
|-ora_login_user:登陆用户名
|-ora_sysevent:返回触发触发器的系统事件名
|-常用系统触发
|-开户关闭数据库时进行记录
CREATE TABLE sysevent_recored(
event VARCHAR2(100),
TIME DATE
);
CREATE OR REPLACE TRIGGER tr_startup
AFTER startup
ON DATABASE
BEGIN
INSERT INTO sysevent_recored VALUES(ora_sysevent, SYSDATE);
END;
CREATE OR REPLACE TRIGGER tr_shutdown
BEFORE SHUTDOWN
ON DATABASE
BEGIN
INSERT INTO sysevent_recored VALUES(ora_sysevent, SYSDATE);
END;
|-进行用户登陆退出触发
CREATE TABLE log_record(
username VARCHAR2(30),
logon_time DATE,
logoff_time DATE,
address VARCHAR2(100)
);
CREATE OR REPLACE TRIGGER tr_logon
AFTER logon
ON DATABASE
BEGIN
INSERT INTO log_record VALUES(username, logon_time, address) VALUES( ora_login_user, SYSDATE, ora_client_ip_address);
END;
CREATE OR REPLACE TRIGGER tr_logoff
BEFORE logoff
ON DATABASE
BEGIN
INSERT INTO log_record VALUES(username, logoff_time, address) VALUES( ora_login_user, SYSDATE, ora_client_ip_address);
END;
|-触发器管理
|-显示触发器信息
|-SELECT status, ut.* FROM User_Triggers ut;
|-禁止
|-ALTER TRIGGER TR_LOGOFF DISABLE;
|-针对某表的所有触发器生效:ALTER TABLE student DISABLE ALL TRIGGERS;
|-激活
|-ALTER TRIGGER TR_LOGOFF ENABLE;
|-ALTER TABLE student ENABLE ALL TRIGGERS;
|-重新编译
|-针对表结构发生变化后,触发器进行INVALID状态,需重新编译进行触发:ALTER TRIGGER TR_STUDENT_DML COMPILE;
|-删除
|-DROP TRIGGER TR_STUDENT_DML;
|-事务控制
|-实质
|-在Oracle的每个连接中都会产生一个Session,一个Session对数据库的修改,不会立刻反应到数据库的真实数据上,是允许回滚的。只有当提交了,才会变成持久数据。
|-原子性
|-一个事务中,包含的若干个操作是一个整体需一起完成实现。
|-一致性
|-事务未提交前,修改用户和其它用户所见一致,其中其它用户所见一致。
|-隔离性
|-未完成的事务不可见
|-持久性
|-事务提交后数据更新为持久数据
|-用户管理
|-创建用户
|-CREATE USER test IDENTIFIED BY test;
|-删除用户
|-
|-创建Session权限
|-分配连接权限,但还不能进行任何操作:GRANT CREATE SESSION TO test;
|-用户角色
|-GRANT
CONNECT, --连接
RESOURCE, --基本的业务表等的创建
UNLIMITED TABLESPACE, --表空间操作
--DBA, --所有数据库权限集合,不建议
SELECT_CATALOG_ROLE, --查询数据字典视图和包
EXP_FULL_DATABASE,
IMP_FULL_DATABASE --数据导入导出工具的使用
TO test;
|-锁定用户
|-ALTER USER test ACCOUNT LOCK --UNLOCK
|-密码失效
|-密码失效,会提示输入新密码:ALTER USER test PASSWORD EXPIRE;
|-对象授权
|-GRANT SELECT ON yqj.student TO test;
|-GRANT ALL ON yqj.student TO test; --提供表的所有权限
|-GRANT UPDATE(sid) ON yqj.student TO test; --控制到列权限
|-权限回收
|-注意只能回收表层次的权限,如对列的控制无法回收:REVOKE ALL ON yqj.student FROM test;
|-查看权限
|-查看当前用户权限信息:SELECT * FROM user_sys_privs;
|-权限传递
|-权限sys->test->next,而移除test权限后,不影响next的权限:GRANT CREATE SESSION TO test WITH ADMIN OPTION;
|-角色
|-CREATE ROLE testRole;
|-GRANT CREATE TABLE TO testRole;
|-DROP ROLE testRole;
|-完整流程
|-
--创建表空间
CREATE TABLESPACE test
DATAFILE 'D:\oracle\product\10.2.0\oradata\orcl\test.ora'
SIZE 200M
AUTOEXTEND ON NEXT 50M
EXTENT MANAGEMENT LOCAL
SEGMENT SPACE MANAGEMENT AUTO;
CREATE TEMPORARY TABLESPACE test_temp
TEMPFILE 'D:\oracle\product\10.2.0\oradata\orcl\test_temp.dbf'
SIZE 50M
AUTOEXTEND ON NEXT 50M
EXTENT MANAGEMENT LOCAL;
--增加相关用户及权限
CREATE USER test IDENTIFIED BY test
DEFAULT TABLESPACE test
TEMPORARY TABLESPACE test_temp;
--增加相关用户权限
GRANT ALL PRIVILEGES TO test;
--测试连接
SELECT * FROM user_sys_privs;
|-备份 恢复 SQLLDR
|-IMP/EXP
|-
--完全导出/导入,导出整个数据库
EXP/IMP YQJ/YQJ BUFFER=64000 FILE= D:\FULL.DMP FULL= Y;
--导出/导入指定用户信息
EXP/IMP YQJ/YQJ BUFFER=64000 FILE= D:\YQJ.DMP OWNER= YQJ;
--导出/导入指定用户信息下的指定表
EXP/IMP YQJ/YQJ BUFFER=64000 FILE=D:\YQJ_STUDENT.DMP TABLES=(STUDENT); --OWNER=orcl
|-SQLLDR
|-整理数据至CSV
|- NAME AGE ADDRESS CARDNO
1 23 福建省 350582198903164000
2 24 福建省 350582198903164001
3 25 福建省 350582198903164002
4 26 福建省 350582198903164003
|-创建对应表
|-CREATE TABLE sqlloader(
NAME VARCHAR2(100) NOT NULL,
age NUMBER(3) CHECK(age<300 AND age> 18),
address VARCHAR2(300),
cardNo VARCHAR2(50) UNIQUE NOT NULL
);
|-创建控制文件sqlloader.ctl
|-load DATA --控制文件标识
infile 'd:\sqlloader.csv' --输入的数据文件名
append INTO TABLE sqlloader --向表追加记录
--insert为缺省方式,要求表为空
--replace/truncate,删除旧记录并替换
fields terminated BY ","
optionally enclosed BY '"'
(NAME, age, address, cardNo)--对应表单的字段名称
|-CMD执行调用语句
|-sqlldr userid=yqj/yqj control= d:\sqlloader.ctl
|-数据库设计范式
|-字段设计为不可再分
|-两张表的关系,在第三张表中体现
|-多张表中,只存关系,不存具体信息
|-表关联越少越好,SQL语句复杂度越低越好
|-Oracle跨库查询
|-建立DBlink
|-情况一:
|-本地tnsnames.ora已配置如下
|-bylw =
(DESCRIPTION =
(ADDRESS_LIST =
(ADDRESS = (PROTOCOL = TCP)(HOST = 192.168.1.5)(PORT = 1521))
)
(CONNECT_DATA =
(SERVER = DEDICATED)
(SERVICE_NAME = bylw)
)
)
|-登陆创建链接
|-create public database link
to_bylw connect to scott identified by tiger using 'bylw';
|-情况二:
|-本地tnsnames.ora中未配置
|- create database link to_test
connect to scott identified by tiger
using '(DESCRIPTION =
(ADDRESS_LIST =
(ADDRESS = (PROTOCOL = TCP)(HOST = 192.168.1.5)(PORT = 1521))
)
(CONNECT_DATA =
(SERVER = DEDICATED)
(SERVICE_NAME = bylw)
)
)';
|-使用方式如下
|-select * from scott.tb_test@to_bylw;