本文大纲
除表以外,Oracle 还提供了视图、函数、存储过程、包/包体、序列、触发器、作业等对象,以满足数据库业务需要。对大多数应用程序而言,这些对象都只会少量用用,本文也只介绍创建和删除这些对象的基本 SQL 语法,不会深入探讨这些对象的详细语法和具体应用。
视图
创建视图
实际操作过程中,我发现 Oracle 视图有一个问题,就是不大方便注释,每次写好的注释执行之后再打开视图定义所有注释就全都没了。后来我发现把注释写到末尾就不会被清除,但这样总感觉乖乖的,而且我没见谁这么用过,我也很少用,目前还不知道有没有其它问题。创建视图示例:
CREATE OR REPLACE VIEW v_staff2 AS
SELECT t1.staff_id,t1.staff_name,t1.dept_code,t2.enum_name dept_name,t1.gender,
t1.birthday,EXTRACT(YEAR FROM SYSDATE)-EXTRACT(YEAR FROM t1.birthday) age,
t1.edu_bg,t1.base_salary,t1.post_salary,base_salary+post_salary fixed_salary
FROM demo.t_staff t1
LEFT JOIN demo.t_field_enum t2 ON t1.dept_code=t2.enum_code AND t2.field_code='DEPT'
WHERE t1.is_disabled=0
-- 在职员工档案视图
;
查询视图的方法与查询表的方法完全相同,就不再赘述。
函数
创建函数
CREATE OR REPLACE FUNCTION fn_today2
RETURN DATE IS
v_today DATE;
-- 返回当前日期(为了方便演示,假定当前日期始终为 fn_today)
BEGIN
v_today:=TO_DATE('2017-01-10','yyyy-mm-dd');
RETURN v_today;
END;
调用函数
在 Oracle 中调用函数,大概有三种方式。如调用函数 fn_today,示例:
-- 方式一
SELECT fn_today res FROM DUAL; -- res:2017-01-10
-- 方式二
BEGIN
DBMS_OUTPUT.PUT_LINE('res:'||TO_CHAR(fn_today,'yyyy-mm-dd')); -- res:2017-01-10
END;
-- 方式三
DECLARE
v_today DATE;
BEGIN
v_today:=fn_today;
DBMS_OUTPUT.PUT_LINE('res:'||TO_CHAR(fn_today,'yyyy-mm-dd')); -- res:2017-01-10
END;
过程
创建过程
创建一个带自制事物过程,示例:
CREATE OR REPLACE PROCEDURE sp_sync_staff90
AS
v_sql VARCHAR2(200); -- SQL语句
PRAGMA AUTONOMOUS_TRANSACTION;
BEGIN
v_sql:='TRUNCATE TABLE t_staff_young'; -- 清空 90 后职员表
EXECUTE IMMEDIATE v_sql; -- PLSQL 中不能直接执行 DDL 语句
COMMIT;
INSERT INTO t_staff_young
SELECT t1.staff_id,t1.staff_name,t1.dept_code,t1.gender
FROM t_staff t1
WHERE t1.birthday>=TO_DATE('1990-01-01','yyyy-mm-dd');
COMMIT;
END;
创建一个带返回值过程,示例:
CREATE OR REPLACE PROCEDURE sp_staff_status
(
p_staff_id NUMBER, -- 职员ID
p_result OUT VARCHAR2 -- 返回职员状态信息
)
AS
v_staff_status NUMBER(1);
BEGIN
IF (p_staff_id IS NULL OR p_staff_id<0) THEN
p_result:='查无此员工!';
ELSE
SELECT t.is_disabled INTO v_staff_status FROM demo.t_staff t WHERE t.staff_id=p_staff_id;
END IF;
-- 如果用户没有对应权限则给出具体提示
IF v_staff_status=0 THEN
p_result:='该员工在职!';
ELSE
p_result:='该员工已离职!';
END IF;
END;
调用过程
在 PLSQL 的 SQL 窗口中调用无参过程的示例:
BEGIN
sp_sync_staff90; -- 这里必须加分号,否则有语法错误
END;
在 PLSQL 的 SQL 窗口中调用有参数过程的示例:
DECLARE res VARCHAR2(100);
BEGIN
sp_staff_status(2,res);
DBMS_OUTPUT.PUT_LINE('res:'||res); -- res:该员工在职!
END;
包
我有到网上去查询 Oracle 中包的用途,结论是:它就像一个容器,可以将一组逻辑相关过程、函数、变量、常量和游标等 PLSQL 程序设计元素放到一起。包由包规范和包体两个部分组成,包规范用于定义公用的常量、变量、过程和函数,包体用户存放过程和函数的定义。
关于包的好处,网上大多是从程序模块化管理的角度来阐述的,比如说方便查询和维护过程和函数等等。我本人从未系统学过 Oracle,原本也不知道 Oracle 中包的存在,后来为写一个触发器来实现在一个批量操作(可能是新增、修改或删除)之后,同时更新另一个表中两个不同字段,更新的条件也不同,条件里需要对第一个表中的数据做聚合操作。如果我没记错的话,应该是添加可以更新,修改和删除不可以更新,如果更新语句执行之后立即提交,语法上又通不过(后来我分析这本身也是矛盾的),总之怎么写都不对。我告诉经理这条路可能走不通,然后把我的分析给他讲了一下,他也觉得我说的有道理。接下来我们开始查资料、找解决方案,经理先找到包变量的用法,并做了个测试认为可行,于是我也照模画样,把已经删掉或改过的数据外键保存到包变量中,再到触发器中去取,发现果然可行,我也这么偶然的接触到 Oracle 中的包。
创建包/包体
创建一个包含包变量的包规范,示例:
CREATE OR REPLACE PACKAGE pkg_staff AS -- 这里还可以用 IS 代替 AS
staff_id NUMBER(10); -- 包变量,职员ID
staff_name VARCHAR2(20); -- 包变量,职员名称
END;
创建一个包含函数的包规范,示例:
CREATE OR REPLACE PACKAGE pkg_case AS
FUNCTION fn_today RETURN DATE; -- 定义函数 fn_today
END;
创建包规范 pkg_case 的包体,示例:
CREATE OR REPLACE PACKAGE BODY pkg_case AS
FUNCTION fn_today
RETURN DATE IS
v_today DATE;
-- 返回当前日期(为了方便演示,假定当前日期始终为 fn_today)
BEGIN
v_today:=TO_DATE('2017-01-10','yyyy-mm-dd');
RETURN v_today;
END;
END;
注意:必须先创建包规范,然后再创建包体。
调用包/包体
调用包里的数据库对象与调用普通的数据库对象方式类似,唯一的区别就是要带上包名前缀(包名.包成员名),调用 pkg_case 包里的 fn_today 函数,示例:
SELECT pkg_case.fn_today FROM DUAL; -- res:2017-01-10
总结
删除数据库对象
删除视图、函数、过程、包等数据库对象的语法相似,示例:
DROP VIEW v_staff2;
DROP FUNCTION fn_today2;
DROP PROCEDURE sp_sync_staff90;
DROP PACKAGE [BODY] pkg_staff;
编译数据库对象
视图、函数、过程、包等数据库对象依赖于基础表的存在而存在,当基础表进行了结构上的修改后,有可能会对这些数据库对象产生影响,有时候这些对象甚至会直接挂掉(在 PLSQL Developer 里看的话,对象名左上角会有一个红色的星号),所以需要对相关数据库对象重新进行编译。
只要拥有 ALTER ANY PROCEDURE 权限,就可以编译视图、函数、过程、包等数据库对象,编译语法大致相似,示例示例
ALTER VIEW v_staff COMPILE; -- 编译 v_staff 视图
ALTER FUNCTION fn_today COMPILE; -- 编译 fn_today 函数
ALTER PROCEDURE sp_staff_status COMPILE; -- 编译 sp_staff_status 过程
ALTER PACKAGE pkg_case COMPILE [PACKAGE|BODY]; -- 编译 pkg_case 包
有时候挂掉的过程太多,如果挨个手动编译效率太低,可以用下面这个过程实现批量编译。
CREATE OR REPLACE PROCEDURE compile_invalid_views(
p_owner VARCHAR2 -- 所有者(schema)名称
)
-- 功能:批量编译某个用户下所有状态无效的过程
AS
v_sql VARCHAR2(400);
BEGIN
FOR invalid_procs IN(
SELECT t.object_name FROM all_objects t
WHERE t.status='INVALID' AND t.object_type='PROCEDURE' AND t.owner=UPPER(p_owner) -- 这里不能加分号,加了会有语法错误
) LOOP
v_sql:='ALTER PROCEDURE '||invalid_procs.object_name||' COMPILE';
BEGIN
EXECUTE IMMEDIATE v_sql;
EXCEPTION
WHEN OTHERS THEN
dbms_output.put_line(SQLERRM);
END;
END LOOP;
END;
如果要编译其它类型对象,只需把过程中的'PROCEDURE'换成对应类型即可。
本文声明:如果您认为这篇文章还可以或对您有帮助,请点击文章末尾的“推荐”按钮。欢迎转载、演绎或用于商业目的,但必须保留本文的署名韩宗泽,并且要在明显位置给出原文链接!本人初写博客,水平有限,若有不当之处,敬请批评指正,谢谢!
.Net程序员学用Oracle系列(7):视图、函数、过程、包的更多相关文章
-
.Net程序员学用Oracle系列:视图、函数、存储过程、包
1.视图 在实际操作过程中,本人发现 Oracle 视图定义有一个缺陷,就是不大方便注释,每次写好的注释执行之后再打开视图定义所有注释就全都没了.后来我发现把注释写到末尾就不会被清除,但这样总感觉乖乖 ...
-
.Net程序员学用Oracle系列(1):导航目录
本人从事基于 Oracle 的 .Net 企业级开发近三年,在此之前学习和使用的都是 (MS)SQL Server.未曾系统的了解过 Oracle,所以长时间感到各种不习惯.不方便.怪异和不解,常会遇 ...
-
.Net程序员学用Oracle系列(2):准备测试环境
<.Net程序员学用Oracle系列:导航目录> 本文大纲 1.创建说明 1.1.为什么要创建的测试环境? 1.2.了解 Oracle 实例的默认用户 2.创建环境 2.1.创建基本环境 ...
-
.Net程序员学用Oracle系列(6):表、字段、注释、约束、索引
<.Net程序员学用Oracle系列:导航目录> 本文大纲 1.表 1.1.创建表 1.2.修改表 & 删除表 2.字段 2.1.添加字段 2.2.修改字段 & 删除字段 ...
-
.Net程序员学用Oracle系列(8):触发器、任务、序列、连接
<.Net程序员学用Oracle系列:导航目录> 本文大纲 1.触发器 1.1.创建触发器 1.2.禁用触发器 & 启用触发器 & 删除触发器 2.任务 2.1.DBMS_ ...
-
.Net程序员学用Oracle系列(9):系统函数(上)
<.Net程序员学用Oracle系列:导航目录> 本文大纲 1.字符函数 1.1.字符函数简介 1.2.语法说明及案例 2.数字函数 2.1.数字函数简介 2.2.语法说明及案例 3.日期 ...
-
.Net程序员学用Oracle系列(10):系统函数(下)
<.Net程序员学用Oracle系列:导航目录> 本文大纲 1.转换函数 1.1.TO_CHAR 1.2.TO_NUMBER 1.3.TO_DATE 1.4.CAST 2.近似值函数 2. ...
-
.Net程序员学用Oracle系列(11):系统函数(下)
1.聚合函数 1.1.COUNT 函数 1.2.SUM 函数 1.3.MAX 函数 1.4.MIN 函数 1.5.AVG 函数 2.ROWNUM 函数 2.1.ROWNUM 函数简介 2.2.利用 R ...
-
.Net程序员学用Oracle系列(15):DUAL、ROWID、NULL
1.DUAL 表 2.ROWID 类型 2.1.利用 ROWID 查询数据 2.2.利用 ROWID 更新数据 3.NULL 值 3.1.NULL 与空字符串 3.2.NULL 与函数 3.3.NUL ...
随机推荐
-
rake :You have already activated rake 10.1.0
rake aborted! You have already activated rake 10.1.0, but your Gemfile requires rake 10.0.3. Using b ...
-
linux 驱动学习笔记03--Linux 内核的引导
如图所示为 X86 PC 上从上电/复位到运行 Linux 用户空间初始进程的流程.在进入与 Linux相关代码之间,会经历如下阶段. ( 1 ) 当系统上电或复位时, CPU 会将 PC 指针赋值为 ...
-
加密–RSA前端与后台的加密&;解密
1. 前言 本问是根据网上很多文章的总结得到的. 2. 介绍 RSA加密算法是一种非对称加密算法. 对极大整数做因数分解的难度决定了RSA算法的可靠性.换言之,对一极大整数做因数分解愈困难,RSA算法 ...
-
14、Silverlight 滤镜到 UWP 滤镜的移植(二)
上一篇文章 大致介绍了,移植戴震军大哥的 Windows Phone7 中,对于高斯模糊滤镜的移植,主要是 int[] 数组和 byte[] 数组的互相转换.同样的思路,只要把前文的方法封装一下,就能 ...
-
Recommender Systems协同过滤
第一部分是学习ID3时候积累的. 一.以前写的基础知识 1.信息:是用来消除不确定性的度量,信息量的大小,由所消除的不确定性的大小来计量(香农). 2.由于不确定性是由随机性引起的,所以用概率来描述和 ...
-
sql存储过程exec执行字符串select 的区别
USE [GuangHong]GO/****** Object: StoredProcedure [dbo].[st_MES_SelInspctDetail] Script Date: 11/23/2 ...
-
大硬盘(大于2T)分区方法
背景 在使用fdisk建立分区时,我们最大只能建立2TB大小的分区.如需建立超过2T的分区需要采用GPT磁盘模式.下文补充一下GPT和MBR的基础知识和分超过2T分区的方法. 基本概念 MBR 1.M ...
-
89、instancetype和id的区别
1>instancetype在类型表示上,跟id一样,可以表示任何对象类型 2>instancetype只能用在返回值类型上,不能像id一样用在参数类型上 3>instancetyp ...
-
Python 在 Terminal 中的自动补全
为了在 Terminal 中使用 Python 更加方便,在 home 目录下添加脚本 .pythonstartup,内容如下, 然后在 .bashrc 中添加 export PYTHONSTARTU ...
-
Mybatis的mapper文件中#和$的区别 以及 resultType和resultMap的区别
一般#{}用于传递查询的参数,一般用于从dao层传递一个string或者其他的参数过来,mybatis对这个参数会进行加引号的操作,将参数转变为一个字符串. SELECT * FROM employe ...