目录
数据查询以及伪列、伪表
Oracle连接方式
常用运算符
集合操作符
Oracle函数
日期函数:
字符函数:
数字函数:
转换函数:
其它函数:
分组函数:
分析函数
数据库对象
同义词
序列
视图
索引
PL/SQL块
游标触发器
游标
触发器
创建触发器的语法:
触发器由三部分组成:
子程序和程序包
子程序
子程序的优点:
过程
函数
程序包和程序包主体
程序包
程序包规范
程序包的优点
程序包中的游标
内置程序包
程序包主体
子程序和程序包总结:
A. { 查询不重复的数据:Distinct 连接运算符:|| 运算符:(+ - * / mod) }
B.{ 伪列:rowid 是表中行的存储地址,该地址可以唯一地标识数据库中的一行,可以使用rowid快速地定位表中的一行 rownum 是查询返回的结果集中行的序号,可以使用它来限定查询返回的行数
伪表:dual }
C.{ 单列排序:order by deptno desc 多列排序: order by deptno desc,sal asc }
D.{ 连接 》》》 左:left join 右:right join 内:inner join 全:full join
自连接 》》》 应用场合:同一表中的字段与字段之间存在引用关系 注意:自连接时需要给表指定别名 例:查询员工‘SMITH’ 的上级领导的姓名 select 领导表.ename from emp 员工表,emp 领导表 where 员工表.ename=‘SMITH’ and 员工表.mgr=领导表.empno; }
E.{ 比较运算符 模糊查询like-通配符 %表示匹配任意个字符 _表示匹配单个字符 In(值列表) 表示查询在指定的值列表范围内的数据 is null判断是否为空 例:查询没有上级的员工信息 Between…and 判断是否在两值之间 例:查询薪水在2000-3000之间的员工信息 与not连用表示取否定 not like,not in,is not null,not between 逻辑运算符 连接多个比较运算的结果以生成一个或真或假的结果。 包括and(与),or(或),not(非) 例:查询薪水高于2000或者岗位为CLERK的员工信息,同时还要满足其姓名首字母为大写J }
F.{ 将两个查询的结果组合成一个结果集 Union(联合) 返回两个查询选定的所有的不重复的行 Union all(联合所有) 返回两个查询选定的所有行,包括重复行 Intersect(交集) 返回两个查询都有的行 Minus(减集) 返回由第1个查询选定但是没有被第2个查询选定的行。 即:在第1个结果集中减去在第2个结果集中出现的行
注意:集合操作符联接的各个查询要具有相同的列数,且对应列的数据类型必须相同。 }
Add_Months(d,n) 1:d-日期,n-月数 2:返回给指定日期加上指定月数后的日期值 Months_Between(d1,d2) 返回两个日期之间的月数 Last_Day(d) 返回指定日期当月的最后一天的日期值 Round(d[,fmt]) 返回四舍五入后的日期值 Next_Day(d,day) 返回指定日期之后的星期几的日期 Extract(fmt from d) 提取日期时间类型中的特定部分
Initcap(char) | Select initcap(‘hello’) from dual; | Hello |
---|---|---|
Lower(char) | Select lower(‘FUN’) from dual; | fun |
Upper(char) | Select upper(‘sun’) from dual; | SUN |
Ltrim(char,set) | Select ltrim( ‘xyzadams’,’xyz’) from dual; | adams |
Rtrim(char,set) | Select rtrim(‘xyzadams’,’ams’) from dual; | xyzad |
Translate(char, from, to) | Select translate(‘jack’,’j’ ,’b’) from dual; | back (只1对1) |
Replace(char, searchstring,[rep string]) | Select replace(‘jack and jue’ ,’j’,’bl’) from dual; | black and blue |
Instr (char, m, n) | Select instr (‘worldwide’,’d’) from dual; | 5 (indexOf) |
Substr (char, m, n) | Select substr(‘abcdefg’,3,2) from dual; | cd |
Concat (expr1, expr2) | Select concat (‘Hello’,’ world’) from dual; | Hello world |
Abs(n) | Select abs(-15) from dual; | 15 |
---|---|---|
Ceil(n) | Select ceil(44.778) from dual; | 45 |
Cos(n) | Select cos(180) from dual; | -.5984601 |
Cosh(n) | Select cosh(0) from dual; | 1 |
Floor(n) | Select floor(100.2) from dual; | 100 |
Power(m,n) | Select power(4,2) from dual; | 16 |
Mod(m,n) | Select mod(10,3) from dual; | 1 |
Round(m,n) | Select round(100.256,2) from dual; | 100.26 |
Trunc(m,n) | Select trunc(100.256,2) from dual; | 100.25 |
Sqrt(n) | Select sqrt(4) from dual; | 2 |
Sign(n) | Select sign(-30) from dual; | -1 |
TO_CHAR:数值型或者日期型转化为字符型 TO_DATE:字符型转换为日期型 TO_NUMBER:将字符串转换为数值型的格式
select to_char(6666.3333,'0000') from dual;
select to_char(sysdate,'YYYY"年"fmMM"月"fmDD"日"') from dual;
select to_char(empno,'C99999') from emp;
select to_date('2003-10-09','yyyy-mm-dd') from dual;
select to_number('100') from dual;
处理null值和零值 Nvl(exp1,exp2) 将空值替换为指定的值 如果exp1为null,则返回exp2,否则返回exp1 例:查询所有员工的年薪和年奖金之和 Nvl2(exp1,exp2,exp3) 如果exp1不为null,则返回exp2,否则返回exp3 Nullif(exp1,exp2) 如果exp1=exp2,则返回null,否则返回exp1
GROUP BY子句 用于将信息划分为更小的组 每一组行返回针对该组的单个结果 注意:在包含Group by子句的查询中,select子句中列表的项只能是聚合函数、Group by表达式( 分组字段或表达式)、常数或包含上述项之一的表达式。 HAVING子句 用于指定 GROUP BY 子句检索行的条件 ORDER BY 字句 ASC 升序 DESC 降序
对分组后的数据进行筛选 AVG 求平均值 MIN 取最小 MAX 取最大 SUM求和 count计数
ROW_NUMBER 返回连续的排位,不论值是否相等 RANK 具有相等值的行排位相同,序数随后跳跃 DENSE_RANK 具有相等值的行排位相同,序号是连续的
#私有同义词
CREATE SYNONYM emp FOR SCOTT.emp;
#公有同义词
CREATE PUBLIC SYNONYM emp_syn FOR SCOTT.emp;
#删除同义词
DROP SYNONYM emp;
DROP PUBLIC SYNONYM emp_syn;
#替换现有的或创建同义词 查询同义词
CREATE OR REPLACE SYNONYM emp_syn FOR SCOTT.emp;
select * from emp_syn;
创建序列
CREATE SEQUENCE toys_seq
START WITH 10 指定第一个序号从10开始
INCREMENT BY 10 指定序号之间的间隔为10
MAXVALUE 2000 表示序列的最大值为2000
MINVALUE 10 表示序列的最小值为10
NOCYCLE 在达到最大值后停止生成下一个值
CACHE 10; 指定内存中预先分配的序号数
ALTER SEQUENCE toys_seq MAXVALUE 5000 CYCLE; 使用ALTER SEQUENCE语句修改序列,
不能更改序列的START WITH参数
DROP SEQUENCE toys_seq; 删除序列
CREATE [OR REPLACE] [FORCE] VIEW 创建视图
view_name [(alias[, alias]...)]
AS select_statement
[WITH CHECK OPTION]
[WITH READ ONLY];
在视图上也可以使用修改数据的DML语句,如INSERT、UPDATE和DELETE
视图上的DML语句有如下限制:
只能修改一个底层的基表
如果修改违反了基表的约束条件,则无法更新视图
如果视图包含连接操作符、DISTINCT 关键字、集合操作符、聚合函数或 GROUP BY 子句,则将无法更新视图
如果视图包含伪列或表达式,则将无法更新视图
DROP VIEW view_name; 删除视图
CREATE INDEX item_index ON itemfile (itemcode); 创建索引
ALTER INDEX item_index REBUILD; 重建索引
DROP INDEX item_index; 删除索引
CREATE INDEX index_reverse_empno ON emp(empno) REVERSE; 反向键索引
CREATE BITMAP INDEX index_bit_job ON emp(job); 位图索引
CREATE UNIQUE INDEX item_index ON itemfile (itemcode); 唯一索引
CREATE INDEX comp_index
ON itemfile(p_category, itemrate); 组合索引
与索引有关的数据字典视图有:
USER_INDEXES - 用户创建的索引的信息
USER_IND_PARTITIONS - 用户创建的分区索引的信息
USER_IND_COLUMNS - 与索引相关的表列的信息
DECLARE
p_empno NUMBER;
p_name VARCHAR2(20);
p_sal NUMBER;
c_rate CONSTANT NUMBER := 0.10;
BEGIN
...
p_empno:= 7366;
SELECT ename, sal * c_rate
INTO p_name, p_sal
FROM emp WHERE empno = p_empno;
...
END;
PL/SQL 支持的流程控制结构:
条件控制 | 顺序控制
IF 语句 | GOTO 语句
CASE 语句 | NULL 语句
循环控制
LOOP 循环
WHILE 循环
FOR 循环
输出语句:
DBMS_OUTPUT.PUT_LINE('itemrate='|| irate);
异常语句:
raise_application_error(-20820,'*******');
条件控制:
A、 IF irate > 200 THEN
UPDATE itemfile SET itemrate = itemrate - 200
WHERE itemcode = icode;
ELSE
UPDATE itemfile SET itemrate = itemrate - 50
WHERE itemcode = icode;
END IF;
B、 CASE ‘&grade’
WHEN ’A’ THEN DBMS_OUTPUT.PUT_LINE(’优异’);
WHEN ’B’ THEN DBMS_OUTPUT.PUT_LINE (优秀’);
ELSE DBMS_OUTPUT.PUT_LINE (’没有此成绩’);
END CASE;
循环控制:
A、LOOP
sequence_of_statements
END LOOP;
B、WHILE condition LOOP
sequence_of_statements
END LOOP;
C、FOR e_emp or (counter) IN [REVERSE] v_emp or(value1..value2) LOOP
sequence_of_statements
END LOOP;
顺序控制:
IF qtyhand < relevel THEN
GOTO updation;
ELSE
GOTO quit;
END IF;
<>
UPDATE itemfile SET qty_hand = qty_hand + re_level
WHERE itemcode = 'i201';
<>
NULL;
动态SQL:
DECLARE
sql_stmt VARCHAR2(200);
emp_id NUMBER(4) := 7566;
emp_rec emp%ROWTYPE;
BEGIN
EXECUTE IMMEDIATE
'CREATE TABLE bonus1 (id NUMBER, amt NUMBER)';
sql_stmt := 'SELECT * FROM emp WHERE empno = :id';
EXECUTE IMMEDIATE sql_stmt INTO emp_rec USING emp_id;
END;
%NOTFOUND 如果FETCH语句失败,则该属性为"TRUE",否则为"FALSE"; %FOUND 如果FETCH语句成功,则该属性为"TRUE",否则为"FALSE"; %ROWCOUNT 返回游标当前的行数; %ISOPEN 如果游标是开的则返回"TRUE",否则为"FALSE";
创建隐式游标:
DECLARE
v_TOYID TOYS.ID%type := '&TOYID';
v_TOYNAME TOYS.NAME%Type := '&TOYNAME';
BEGIN
UPDATE TOYS SET NAME = v_TOYNAME
WHERE toyid=v_TOYID;
IF SQL%NOTFOUND THEN
DBMS_OUTPUT.PUT_LINE('编号未找到。');
ELSE
DBMS_OUTPUT.PUT_LINE(‘表已更新');
END IF;
END;
创建显示游标:
DECLARE
v_sal emp.sal%TYPE;
CURSOR c_cur IS SELECT sal FROM emp WHERE sal<2500;
BEGIN
OPEN c_cur;
FOR toy_rec IN c_cur LOOP 循环游标
DBMS_OUTPUT.PUT_LINE(
‘玩具编号:'||' ' ||toy_rec.toyid||' '
||‘玩具名称:'||' '||toy_rec.toyname||' '
||‘玩具单价:'||' '||toy_rec.toyprice);
END LOOP;
LOOP
FETCH c_cur INTO v_sal;
EXIT WHEN c_cur%NOTFOUND;
DBMS_OUTPUT.PUT_LINE
(‘薪水:'||v_sal);
END LOOP;
CLOSE c_cur;
END;
使用有表变量执行动态SQL:
declare
Type salcursor is ref cursor;--声明游标类型
salcurvar salcursor;--定义游标变量
mysal number;
begin
open salcurvar for
‘select sal from myemp where deptno=:dno’--动态SQL
using ‘&no’;--填补占位符的参数
loop
fetch salcurvar into mysal;
exit when salcurvar%notfound;
dbms_output.put_line(mysal);
end loop;
end;
触发器是当特定事件出现时自动执行的存储过程 特定事件可以是执行更新的DML语句和DDL语句 触发器不能被显式调用 触发器的功能: 自动生成数据 自定义复杂的安全权限 提供审计和日志记录 启用复杂的业务逻辑
CREATE [OR REPLACE] TRIGGER trigger_name
AFTER | BEFORE | INSTEAD OF
[INSERT] [[OR] UPDATE [OF column_list]]
[[OR] DELETE]
ON table_or_view_name
[REFERENCING {OLD [AS] old / NEW [AS] new}]
[FOR EACH ROW]
[WHEN (condition)]
pl/sql_block;
行级触发器:
CREATE OR REPLACE TRIGGER BI_TEST_TRG
BEFORE INSERT OR UPDATE OF ID
ON TEST_TRG
FOR EACH ROW
BEGIN
IF INSERTING THEN
SELECT SEQ_TEST.NEXTVAL INTO :NEW.ID FROM DUAL;
ELSE
RAISE_APPLICATION_ERROR(-20020, '不允许更新ID值!');
END IF;
END;
语句级触发器:
CREATE OR REPLACE TRIGGER BI_TEST_TRG
BEFORE INSERT OR UPDATE OF ID
ON TEST_TRG
FOR EACH ROW
BEGIN
IF INSERTING THEN
SELECT SEQ_TEST.NEXTVAL INTO :NEW.ID FROM DUAL;
ELSE
RAISE_APPLICATION_ERROR(-20020, '不允许更新ID值!');
END IF;
END;
INSTEAD OF 触发器:
CREATE OR REPLACE TRIGGER upd_ord_view
INSTEAD OF UPDATE ON ord_view
FOR EACH ROW
BEGIN
UPDATE order_master
SET vencode=:NEW.vencode
WHERE orderno = :OLD.orderno;
DBMS_OUTPUT.PUT_LINE(‘已激活触发器');
END;
触发器语句(事件) 定义激活触发器的 DML 事件和 DDL 事件 触发器限制 执行触发器的条件,该条件必须为真才能激活触发器 触发器操作(主体) 包含一些 SQL 语句和代码,它们在发出了触发器语句且触发限制的值为真时运行
启用、禁用和删除触发器
ALTER TRIGGER aiu_itemfile DISABLE;
ALTER TRIGGER aiu_itemfile ENABLE;
DROP TRIGGER aiu_itemfile;
触发器是当特定事件出现时自动执行的存储过程 触发器分为 DML 触发器、DDL 触发器和数据库级触发器三种类型 DML 触发器的三种类型包括行级触发器、语句级触发器和 INSTEAD OF 触发器
模块化 将程序分解为逻辑模块 可重用性 可以被任意数目的程序调用 可维护性 简化维护操作 安全性 通过设置权限,使数据更安全
过程参数的三种模式:
创建过程的语法
CREATE [OR REPLACE] PROCEDURE 》
[()] 》 创建过程,可指定运
IS|AS 》 行过程需传递的参数。
》
BEGIN
> 包括在过程中要执行的语句
[EXCEPTION
] } 处理异常
END;
执行过程的语法:
EXECUTE procedure_name(parameters_list);
CREATE OR REPLACE PROCEDURE
itemdesc(item_code IN VARCHAR2)
IS
v_itemdesc VARCHAR2(5);
BEGIN
SELECT itemdesc INTO v_itemdesc
FROM itemfile
WHERE itemcode = item_code;
DBMS_OUTPUT.PUT_LINE(item_code||
'项目的说明为'||v_itemdesc);
END;
/
SET SERVEROUTPUT ON
EXECUTE itemdesc('i201');
将过程的执行权限授予其他用户(本用户不受限制)
GRANT EXECUTE ON find_emp TO MARTIN;
GRANT EXECUTE ON swap TO PUBLIC;
删除过程
DROP PROCEDURE find_emp;
函数是可以返回值的命名的 PL/SQL 子程序。 创建函数的语法:
CREATE [OR REPLACE] FUNCTION
[(param1,param2)]
RETURN IS|AS
[local declarations]
BEGIN
Executable Statements;
RETURN result;
EXCEPTION
Exception handlers;
END;
定义函数的限制:
函数只能接受 IN 参数,而不能接受 IN OUT 或 OUT 参数
可以使用伪类型%TYPE、%ROWTYPE
访问函数的两种方式:
使用 PL/SQL 块
使用 SQL 语句
创建函数
CREATE OR REPLACE FUNCTION fun_hello(a number,b varchar2)
RETURN VARCHAR2
IS
BEGIN
RETURN '朋友,您好';
END;
调用函数
SELECT fun_hello(1,'asdf') FROM DUAL;
过 程 | 函 数 |
---|---|
作为 PL/SQL 语句执行**Execute** 执行 | 作为 PL/SQL 语句执行**作为表达式的一部分调用** |
在规格说明中不包含 RETURN 子句 | 必须在规格说明中包含 RETURN 子句**(执行出错)** |
不返回任何值 | 必须返回单个值 |
可以包含 RETURN 语句,但是与函数不同,它不能用于返回值 | 必须包含至少一条 RETURN 语句 |
CREATE [OR REPLACE]
PACKAGE
package_name IS|AS
[Public item declarations]
[Subprogram specification]
END [package_name];
create or replace package toyspack as
--增加单价的过程
procedure updateToyPrice;
--计算平均值的函数
function avgToyPrice return number;
end toyspack;
模块化 更轻松的应用程序设计 信息隐藏 新增功能 性能更佳
游标的定义分为游标规范和游标主体两部分 在包规范中声明游标规范时必须使用 RETURN 子句指定游标的返回类型 RETURN子句指定的数据类型可以是: 用 %ROWTYPE 属性引用表定义的记录类型 程序员定义的记录类型
CREATE OR REPLACE PACKAGE BODY cur_pack AS
CURSOR ord_cur(vcode VARCHAR2)
RETURN order_master%ROWTYPE IS
SELECT * FROM order_master WHERE VENCODE=vcode;
PROCEDURE ord_pro(vcode VARCHAR2) IS
or_rec order_master%ROWTYPE;
BEGIN
OPEN ord_cur(vcode);
LOOP
FETCH ord_cur INTO or_rec;
EXIT WHEN ord_cur%NOTFOUND;
DBMS_OUTPUT.PUT_LIne(’返回的值为' || or_rec.orderno);
END LOOP;
END ord_pro;
END cur_pack;
扩展数据库的功能 为 PL/SQL 提供对 SQL 功能的访问 用户 SYS 拥有所有程序包 是公有同义词 可以由任何用户访问
STANDARD**和DBMS_STANDARD** | 定义和扩展**PL/SQL语言环境** |
---|---|
DBMS_LOB | 提供对 LOB**数据类型进行操作的功能** |
DBMS_OUTPUT | 处理**PL/SQL块和子程序输出调试信息** |
DBMS_RANDOM | 提供随机数生成器 |
DBMS_SQL | 允许用户使用动态 SQL |
DBMS_XMLDOM | 用**DOM模型读写XML类型的数据** |
DBMS_XMLPARSER | XML**解析,处理XML文档内容和结构** |
DBMS_XMLQUERY | 提供将数据转换为 XML 类型的功能 |
DBMS_XSLPROCESSOR | 提供**XSLT功能,转换XML文档** |
UTL_FILE | 用 PL/SQL 程序来读写操作系统文本文件 |
内置程序包
DBMS_OUTPUT包显示 PL/SQL 块和子程序的调试信息。
SQL> BEGIN
DBMS_OUTPUT.PUT_LINE('打印三角形');
FOR i IN 1..9 LOOP
FOR j IN 1..i LOOP
DBMS_OUTPUT.PUT('*');
END LOOP for_j;
DBMS_OUTPUT.NEW_LINE;
END LOOP for_i;
END;
DBMS_LOB包提供用于处理大型对象的过程和函数
DBMS_XMLQUERY包用于将查询结果转换为 XML 格式
SQL> DECLARE
result CLOB;
xmlstr VARCHAR2(32767);
line VARCHAR2(2000);
line_no INTEGER := 1;
BEGIN
result := DBMS_XMLQuery.getXml('SELECT empno, ename
FROM employee');
xmlstr := DBMS_LOB.SUBSTR(result,32767);
LOOP
EXIT WHEN xmlstr IS NULL;
line := SUBSTR(xmlstr,1,INSTR(xmlstr,CHR(10))-1);
DBMS_OUTPUT.PUT_LINE(line_no || ':' || line);
xmlstr := SUBSTR(xmlstr,INSTR(xmlstr,CHR(10))+1);
line_no := line_no + 1;
END LOOP;
END;
DBMS_RANDOM 包可用来生成随机整数
SQL> SET SERVEROUTPUT ON
SQL> DECLARE
l_num NUMBER;
counter NUMBER;
BEGIN
counter:=1;
WHILE counter <= 10
LOOP
l_num := DBMS_RANDOM.RANDOM;
DBMS_OUTPUT.PUT_LINE(l_num);
counter:=counter+1;
END LOOP;
END;
UTL_FILE 包用于读写操作系统文本文件
操作文件的一般过程是打开、读或写、关闭
UTL_FILE 包指定文件路径依赖于 DIRECTORY 对象
SQL> CREATE DIRECTORY TEST_DIR AS 'C:\DEVELOP';
SQL> GRANT READ, WRITE ON DIRECTORY TEST_DIR TO SCOTT;
SQL> SET SERVEROUTPUT ON
SQL> DECLARE
input_file UTL_FILE.FILE_TYPE;
input_buffer VARCHAR2(4000);
BEGIN
input_file := UTL_FILE.FOPEN(
'TEST_DIR', 'employees.xml', 'r');
LOOP
UTL_FILE.GET_LINE(input_file,input_buffer);
DBMS_OUTPUT.PUT_LINE(input_buffer);
END LOOP;
UTL_FILE.FCLOSE(input_file);
EXCEPTION
WHEN NO_DATA_FOUND THEN
DBMS_OUTPUT.PUT_LINE('------------------');
END;
程序包主体规范
CREATE [OR REPLACE] PACKAGE BODY package_name IS|AS
[Private item declarations]
[Subprogram bodies]
[BEGIN
Initialization]
END [package_name];
--创建包体
create or replace package body page210
as
procedure pro_page(
dno number,
clo varchar2,
pageIndex number,
pageSize number,
c_out_cursor out c_ref,
totalCount out number )
as
v_sql varchar2(500);
begin
v_sql:='select * from ( select rownum rn,t.* from (select * from emp where deptno=:1 order by '||clo||' desc) t where rownum<=:3 ) where rn>:4';
--打开游标
open c_out_cursor for v_sql using dno,(pageIndex*pageSize),((pageIndex-1)*pageSize);
--查询总记录数
v_sql:='select count(1) from emp where deptno=:1';
--执行单行
execute immediate v_sql into totalCount using dno;
end pro_page;
end page210;
子程序是命名的 PL/SQL 块,可带参数并可在需要时随时调用 有两种类型的PL/SQL子程序,即过程和函数 过程用户执行特定的任务,函数用于执行任务并返回值 程序包是对相关类型、变量、常量、游标、异常、过程和函数等对象的封装 程序包由两部分组成,即包规范和包主体 使用程序包的优点是:模块化、更轻松的程序设计、信息隐藏、新增功能以及性能更佳