oracle数据库学习笔记
Posted luyang-blog
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了oracle数据库学习笔记相关的知识,希望对你有一定的参考价值。
本文主要参考oracle数据库经典学习教程,对数据库的安装、网络配置不作说明。
一、走进oracle
总结:
Oracle 是基于对象的关系型数据库,Oracle 产品免费,服务收费。 Oracle 安装后默认会有两个管理员用户(system,sys)和一个普通用户 Scott。 Sql*plus 是 Oracle 管理和数据操作的客户端工具。 客户端链接服务器前,服务器要启动监听服务,并且客户端工具要安装 Oracle 客 户端,并且在客户端要建立本地网络服务名。 Oracle 服务和监听启动后才能对数据库进行操作。 用 startup 命令启动数据库,用 shutdown 命令关闭数据库。 Oracle 的角色包括了一系列系统权限和普通对象权限,可以把权限授权给角色,把权限或者角色授权给用户。 |
注意:
管理员用户system的密码为oracle,sys的密码为change_on_install。使用plsql连接时,权限选择为sysdba.
1.oracle服务
OracleService+服务名,该服务是数据库启动的基础,只有该服务启动了,Oracle 数 据库才能正常启动。这是必须启动的服务。
OracleOraDb10g_home1TNSListener,该服务是服务器端为客户端提供的监听服务, 只有该服务在服务器上正常启动,客户端才能连接到服务器。该监听服务接收客户 端发出的请求,然后将请求传递给数据库服务器。一旦建立了连接,客户端和数据 库服务器就能直接通信了。
OracleOraDb10g_home1iSQL*Plus,该服务提供了用浏览器对数据库中数据操作的方 式。该服务启动后,就可以使用浏览器进行远程登录并进行数据库操作了。
OracleDBConsole+服务名,Oracle10g 中的一个新服务。在 Oracle9i 之前,Oracle 官 方提供了一个基于图形界面的企业管理器(EM),从 Oracle10g 开始,Oracle 提供了 一个基于 B/S 的企业管理器,在操作系统的命令行中输入命令:emctl start dbconsole,就可以启动 OracleDbConsole 服务
服务启动之后,就可以在浏览器中输入上图中进入 EM 的地址,使用 B/S 方式管理 Oracle 服务器。
2. Oracle 用户和权限
Oracle 中,一般不会轻易在一个服务器上创建多个数据库,在一个数据库中,不同的项 目由不同的用户访问,每一个用户拥有自身创建的数据库对象,因此用户的概念在 Oracle 中非常重要。Oracle 的用户可以用 CREATE USER 命令来创建。其语法是
语法结构:创建用户
CREATE USER 用户名 IDENTIFIED BY 口令 [ACCOUNT LOCK|UNLOCK]
语法解析:
LOCK|UNLOCK 创建用户时是否锁定,默认为锁定状态。锁定的用户无法正常的登录进 行数据库操作。
尽管用户成功创建,但是还不能正常的登录 Oracle 数据库系统,因为该用户还没有任 何权限。如果用户能够正常登录,至少需要 CREATE SESSION 系统权限。 Oracle 用户对数据库管理或对象操作的权利,分为系统权限和数据库对象权限。系统权限比如:CREATE SESSION,CREATE TABLE 等,拥有系统权限的用户,允许拥有相应的系统操 作。数据库对象权限,比如对表中的数据进行增删改操作等,拥有数据库对象权限的用户可 以对所拥有的对象进行对应的操作。
还有一个概念就是数据库角色(role),数据库角色就是若干个系统权限的集合。下面 介绍几个常用角色:
CONNECT 角色,主要应用在临时用户,特别是那些不需要建表的用户,通常只赋予 他们 CONNECT role。CONNECT 是使用 Oracle 的简单权限,拥有 CONNECT 角色的用 户,可以与服务器建立连接会话(session,客户端对服务器连接,称为会话)。
RESOURCE 角色,更可靠和正式的数据库用户可以授予 RESOURCE role。RESOURCE 提供给用户另外的权限以创建他们自己的表、序列、过程(procedure)、触发器 (trigger)、索引(index)等。
DBA 角色,DBA role 拥有所有的系统权限----包括无限制的空间限额和给其他用户授 予各种权限的能力。用户 SYSTEM 拥有 DBA 角色。
一般情况下,一个普通的用户(如 SCOTT),拥有 CONNECT 和 RESOURCE 两个角色即可 进行常规的数据库开发工作。
可以把某个权限授予某个角色,可以把权限、角色授予某个用户。系统权限只能由 DBA 用户授权,对象权限由拥有该对象的用户授权,授权语法是:
语法结构:授权
GRANT角色|权限 TO 用户(角色)
代码演示:授权
SQL> GRANT CONNECT TO jerry;
授权成功。
SQL> GRANT RESOURCE TO jerry;
授权成功。
SQL>
语法结构:其他操作
//回收权限
REVOKE 角色|权限 FROM 用户(角色)
//修改用户的密码
ALTER USER 用户名 IDENTIFIED BY 新密码
//修改用户处于锁定(非锁定)状态
ALTER USER 用户名 ACCOUNT LOCK|UNLOCK
二、SQL 数据操作和查询
1. SQL 简介
SQL 是结构化查询语言(Structured Query Language),专门用于数据存取、数据更新及数据库管理等操作。
在 Oracle 开发中,客户端把 SQL 语句发送给服务器,服务器对 SQL 语句进行编译、执
行,把执行的结果返回给客户端。Oracle SQL 语句由如下命令组成:
? 数据定义语言(DDL),包括 CREATE(创建)命令、ALTER(修改)命令、DROP(删
除)命令等。
? 数据操纵语言(DML),包括 INSERT(插入)命令、UPDATE(更新)命令、DELETE
(删除)命令、SELECT … FOR UPDATE(查询)等。
?数据查询语言(DQL),包括基本查询语句、Order By 子句、Group By 子句等。
? 事务控制语言(TCL),包括 COMMIT(提交)命令、SAVEPOINT(保存点)命令、
ROLLBACK(回滚)命令。
? 数据控制语言(DCL),GRANT(授权)命令、REVOKE(撤销)命令。
目前主流的数据库产品(比如:SQL Server、Oracle)都支持标准的 SQL 语句。数据定义
语言,表的增删改操作,数据的简单查询,事务的提交和回滚,权限的授权和撤销等,Oracle
与 SQL Server 在操作上基本一致。
2. Oracle 数据类型
Oracle 数据库的核心是表,表中的列使用到的常见数据类型如下:
CHAR(length) 存储固定长度的字符串。参数 length 指定了长度,如果存储的字符串长
度小于 length,用空格填充。默认长度是 1,最长不超过 2000 字节。
VARCHAR2(length) 存储可变长度的字符串。length 指定了该字符串的最大长度。默认长度是 1,最长不超过 4000 字符。
NUMBER(p,s) 既可以存储浮点数,也可以存储整数,p 表示数字的最大位数(如果是
小数包括整数部分和小数部分和小数点,p 默认是 38 为),s 是指小数位数。
DATE 存储日期和时间,存储纪元、4 位年、月、日、时、分、秒,存储时间从公元前 4712 年 1 月 1 日到公元后 4712 年 12 月 31 日。
TIMESTAMP 不但存储日期的年月日,时分秒,以及秒后 6 位,同时包含时区。
CLOB 存储大的文本,比如存储非结构化的 XML 文档
BLOB 存储二进制对象,如图形、视频、声音等。
对应 NUMBER 类型的示例:
格式 |
输入的数字 |
实际的存储 |
NUMBER |
1234.567 |
1234.567 |
NUMBER(6,2) |
123.4567 |
123.46 |
NUMBER(4,2) 12345.67 输入的数字超过了所指定的精度,数据库不能存储对于日期类型,可以使用 sysdate 内置函数可以获取当前的系统日期和时间,返回 DATE
类型,用 systimestamp 函数可以返回当前日期、时间和时区。
Oracle 的查询中,必须使用“select 列… from 表”的完整语法,当查询单行函数的时
候,from 后面使用 DUAL 表,dual 表在系统中只有一行一列,该表在输出单行函数时为了
select…from 的语法完整性而使用。
3. 创建表和约束
Oracle 创建表同 SQL Server 一样,使用 CREATE TABLE 命令来完成。创建约束则使用如下
命令:
语法格式:ALTER TABLE 命令
ALTER TABLE 表名 ADD CONSTRAINT 约束名 约束内容。
4. 数据操纵语言(DML)
数据操纵语言(DML)用于对数据库的表中数据进行添加、修改、删除和 SELECT…For
UPDATE(后面专门学习该查询)操作。Oracle 中的操作。
简单查询
数据查询是用 SELECT 命令从数据库的表中提取信息。SELECT 语句的语法是:
语法结构:简单查询
SELECT *|列名|表达式 FROM 表名 WHERE 条件 ORDER BY 列名
语法解析:
1. *表示表中的所有列。
2. 列名可以选择若干个表中的列名,各个列表中间用逗号分隔。
3. 表达式可以是列名、函数、常数等组成的表达式。
4. WHERE 子句是查询的条件。
5. ORDER BY 要求在查询的结果中排序,默认是升序。
Oracle 中可以把查询的结果根据结果集中的表结构和数据形成一张新表。
语法结构:根据结果集创建表
CREATE TABLE 表名 AS SELECT 语句
代码演示:根据结果集创建表
SQL> CREATE TABLE INFOS1 AS SELECT * FROM INFOS;
TABLE CREATED
使用上面命令创建的新表中,不存在任何约束,并且把查询的数据一起插入到新表中。
如果只复制表结构,只需使查询的条件不成立(比如 where 1=2),就不会查询从出任何数
据,从而复制一个表结构。
代码演示:复制表结构
SQL> CREATE TABLE INFOS2 AS SELECT * FROM INFOS WHERE 1=2;
TABLE CREATED
数据插入
用 INSERT 命令完成对数据的插入。
语法结构:数据插入
INSERT INTO 表名(列名 1,列名 2……) VALUES (值 1,值 2……)
语法解析:
1. 列名可以省略。当省略列名时,默认是表中的所有列名,列名顺序为表定义中列的
先后顺序。
2. 值的数量和顺序要与列名的数量和顺序一致。值的类型与列名的类型一致。
代码演示:向 INFOS 表和 SCORES 表中插入数据
SQL> INSERT INTO INFOS VALUES ( ①
2 ‘s100102‘, ‘林冲‘, ‘男‘, 22, 2,
3 TO_DATE(‘2009-8-9 06:30:10‘,‘ YYYY-MM-DD HH24:MI:SS ‘), ②
4 ‘西安‘, ‘1001‘
5 )
6 /
1 row inserted
SQL> INSERT INTO INFOS VALUES (
‘s100104‘,‘阮小二‘,‘男‘,26,3,SYSDATE,default,‘1001‘); ③
1 row inserted
SQL>COMMIT; ④
代码解析:
① 表名后面缺省了列名,默认是表 Infos 中的所有列名,values 中的值要与表中列一一
对应,包括顺序和数据类型的对应。在 SQL*Plus 中一条语句可以写在多行,那么从
第二行开始,sqlplus 会为每一行前面给出行号。
② 在 Oracle 中,日期是国际化的,不同的区域安装的数据库,默认的日期格式不同,
因此为了程序便于移植,日期的输入要使用 TO_DATE 函数对日期格式化后输入,采
用格式化字符串对日期进行格式化时,格式化字符串中字符不区分大小写,常见的
格式化字符如下:
1. yyyy 表示四位年份
2. mm 表示两位月份,比如 3 月表示为 03
3. dd 表示两位日期
4. hh24 表示小时从 0-23,hh12 也表示小时从 0-11。
5. mi 表示分钟
6. ss 表示秒
③ 在遇到存在默认值的列时,可以使用 default 值代替。
④ commit 是把用户操作(添加、删除、修改操作)提交,只有提交操作后,数据才
能真正更新到表中,否则其他用户无法查询到当前用户操作的结果。
在 Oracle 中,一个 INSERT 命令可以把一个结果集一次性插入到一张表中。使用的语句
是:INSERT INTO 表 SELECT 子句,如下示例:
代码演示:INSERT 向表中插入一个结果集
SQL> INSERT INTO INFOS2 SELECT * FROM INFOS;
5 rows inserted
在这种语法下,要求结果集中每一列的数据类型必须与表中的每一列的数据类型一致,
结果集中的列的数量与表中的列的数量一致。比如表 INFOS2,该表的结构与 INFO 表一样,
那么可以把 INFO 表中的所有记录一次性插入到 INFOS2 表中。
Oracle 的简单查询和 SQL Server 一样都可以在查询列中使用常量,
代码演示:INSERT 向表中插入一个常量结果集
SQL> INSERT INTO INFOS
SELECT ‘s100106‘,‘卢俊义‘,‘男‘,23,5,
TO_DATE(‘2009-8-9 08:00:10‘,‘YYYY-MM-DD HH24:MI:SS‘),
‘青龙寺‘,‘1001‘
FROM DUAL;
1 rows inserted
SQL>COMMIT;
更新数据
Oracle 在表中更新数据的语法是:
语法结构:UPDATE 操作
UPDATE 表名 SET 列名 1=值,列名 2=值…… WHERE 条件
代码演示:UPDATE 操作
SQL> UPDATE INFOS SET CLASSNO=‘1002‘,STUADDRESS=‘山东莱芜‘
WHERE STUNAME=‘阮小二‘;
1 rows updated
SQL> commit;
删除数据
Oracle 在表中删除数据的语法是:
语法结构:DELETE 操作
DELETE FROM 表名 WHERE 条件
代码演示:DELETE 操作
SQL> DELETE FROM INFOS WHERE STUID=‘s100103‘;
1 ROW DELETED
SQL> COMMIT;
TRUNCATE
在数据库操作中, TRUNCATE 命令(是一个 DDL 命令)可以把表中的所有数据一次性
全部删除,语法是:
语法结构:TRUNCATE
TRUNCATE TABLE 表名
TRUNCATE 和 DELETE 都能把表中的数据全部删除,他们的区别是:
1. TRUNCATE 是 DDL 命令,删除的数据不能恢复;DELETE 命令是 DML 命令,删除后
的数据可以通过日志文件恢复。
2. 如果一个表中数据记录很多,TRUNCATE 相对 DELETE 速度快。
由于 TRUNCATE 命令比较危险,因此在实际开发中,TRUNCATE 命令慎用。
5. 操作符
Oracle 开发中,依然存在算术运算,关系运算,和逻辑运算。
算术运算
Oracle 中的算术运算符,没有 C#中的算术运算符丰富,只有+、-、*、/四个,其中除号
(/)的结果是浮点数。求余运算只能借助函数:MOD(x,y):返回 x 除以 y 的余数。
案例 3:每名员工年终奖是 2000 元,请显示基本工资在 2000 元以上的员工的月工资,
年总工资。
该案例的表请参见scott用户,本章练习的附表 1、附表 2、附表 3,这三张表是 ORACLE 10g 自带的。
代码演示:查询中的算术运算
SQL> SELECT ENAME,SAL,(SAL*12+2000) FROM EMP WHERE SAL>2000;
关系运算和逻辑运算
Oracle 中 Where 子句经中经常见到关系运算和逻辑运算,常见的关系运算有:
Oracle 默认安装中,已经创建了一个 SCOTT 用户,默认密码是:tiger,该用户下有四
张表分别是:雇员表(EMP),部门表(DEPT),工资登记表和奖金表,接下来很多操作都是在该用户下完成的。
Oracle 的关系运算符:
运算符 |
说明 |
运算符 |
说明 |
= |
等于 |
> |
大于 |
<>或者!= |
不等于 |
<= |
小于或者等于 |
< |
小于 |
>= |
大于或者等于 |
逻辑运算符有三个:AND、OR、NOT
字符串连接操作符(||)
在 Oracle 中,字符串的连接用双竖线(||)表示。比如,在 EMP 表中,查询工资在 2000
元以上的姓名以及工作。
代码演示:字符串连接
SQL> SELECT (ENAME || ‘is a ‘ || JOB) AS "Employee Details" ① FROM EMP WHERE SAL>2000;
注意:as 可以省略,但是as后边的内容不能使用单引号
代码解析: ① Oracle 中字符串可以用单引号,也可以用双引号,在别名中存在空格时,必须用双 引号。在表名、列名时用双引号。
6. 高级查询
消除重复行
在 Oracle 查询中结果中,可能出现若干行相同的情况,那么可以使用 DISTINCT 消除重
复行。具体的用法如示例:
代码演示:DISTINCT 消除重复行
SQL> SELECT DISTINCT DEPTNO FROM EMP;
NULL 操作
如果某条记录中有缺少的数据值,就是空值(NULL 值)。空值不等于 0 或者空格,空值
是指未赋值、未知或不可用的值。任何数据类型的列都可以包括 NULL 值,除非该列被定义
为非空或者主键。
代码演示:EMP 中的 NULL 值
SQL> SELECT ENAME,JOB,SAL,COMM FROM EMP WHERE SAL<2000;
在查询条件中 NULL 值用 IS NULL 作条件,非 NULL 值用 NOT IS NULL 做条件。
案例 4:查询 EMP 表中没有发奖金的员工。
代码演示:NULL 值查询
SQL> SELECT ENAME,JOB,SAL,COMM FROM EMP WHERE SAL<2000 AND COMM IS NULL;
IN 操作
在 Where 子句中可以使用 IN 操作符来查询其列值在指定的列表中的行。比如:查询出
工作职责是 SALESMAN、PRESIDENT 或者 ANALYST 的员工。条件有两种表示方法:
1. WHERE job = ‘SALESMAN ‘ OR job = ‘PRESIDENT ‘ OR job = ‘ANALYST ‘
2. WHERE job IN (‘SALESMAN‘, ‘PRESIDENT‘, ‘ANALYST‘)
代码演示:IN 操作
SQL> SELECT ENAME,JOB,SAL FROM EMP WHERE job IN (‘SALESMAN‘, ‘PRESIDENT‘, ‘ANALYST‘);
对应 IN 操作的还有 NOT IN,用法一样,结果相反
BETWEEN…AND…
在 WHERE 子句中,可以使用 BETWEEN 操作符来查询列值包含在指定区间内的行。比
如,查询工资从 1000 到 2000 之间的员工。可以使用传统方法:
WHERE SAL>=1000 AND SAL<=2000
也可以使用:
WHERE SAL BETWEEN 1000 AND 2000
BWTWEEN 操作所指定的范围也包括边界。
代码演示:BETWEEN 操作
SQL> SELECT ename,job,sal FROM EMP WHERE sal BETWEEN 1000 AND 2000;
LIKE 模糊查询
字符匹配操作可以使用通配符“%”和“_”:
? %:表示零个或者多个任意字符。
? _:代表一个任意字符。
语法是:LIKE ‘字符串‘[ESCAPE ‘字符‘]。匹配的字符串中,ESCAPE 后面的“字符”作为转
义字符。
通配符表达式 |
说明 |
‘S%‘ |
以S开头的字符串。 |
‘_S%‘ |
第二个字符时S的字符串。 |
‘%30\%%‘ escape ‘\‘ |
包含“30%”的字符串,“\”指转义字符,“\%”在字符串中表示一个字符“%”。 |
案例 5:显示员工名称以 J 开头以 S 结尾的员工的姓名和工资。
代码演示:LIKE 操作
SQL> SELECT ENAME,JOB,SAL FROM EMP WHERE ENAME LIKE ‘J%S‘;
集合运算
集合运算就是将两个或者多个结果集组合成为一个结果集。集合运算包括:
? INTERSECT(交集),返回两个查询共有的记录。
? UNION ALL(并集),返回各个查询的所有记录,包括重复记录。
? UNION(并集),返回各个查询的所有记录,不包括重复记录。
? MINUS(补集),返回第一个查询检索出的记录减去第二个查询检索出的记录之后剩
余的记录。
当使用集合操作的时候,要注意:查询所返回的列数以及列的类型必须匹配,列名可以
不同。
案例 6:查询出 dept 表中哪个部门下没有员工。只需求出 dept 表中的部门号和 emp
表中的部门号的补集即可。
代码演示:求补运算
SQL> SELECT DEPTNO FROM DEPT MINUS SELECT DEPTNO FROM EMP;
前面学习过可以通过 insert into …select 把一个结果集插入到另一张结构相同的表中,因
此可以使用 union 把若干条记录一次性插入到一张表中。
代码演示:用 union 插入多条数据
SQL> INSERT INTO DEPT
SELECT 50,‘公关部‘,‘台湾‘ FROM DUAL
UNION
SELECT 60,‘研发部‘,‘西安‘ FROM DUAL
UNION
SELECT 70,‘培训部‘,‘西安‘ FROM DUAL
连接查询
在 SQL Server 中已经学习过内联接(inner join)、外联接(outer join),外联接又分为左外联
接(left outer join)和右外联接(right outer join)。Oracle 中对两个表或者若干表之间的外联接用
(+)表示。
案例 7:请查询出工资大于 2000 元的,员工姓名,部门,工作,工资。
由于部门名称在 dept 中,其他的信息在 emp 表中,需要内联接才能完成。
代码演示:内联接
SQL> SELECT e.ENAME,e.JOB,e.SAL,d.DNAME
FROM emp e,dept d
WHERE e.deptno=d.deptno
AND e.SAL>2000;
内联接
SELECT e.ENAME,e.JOB,e.SAL,d.DNAME
FROM EMP e INNER JOIN DEPT d ON e.DEPTNO=d.DEPTNO
WHERE e.SAL>2000
这里 INNER JOIN 中,关键字 INNER 可以省略。
请查询出每个部门下的员工姓名,工资。
案例分析:
Emp 表用外键 deptno 引用 Dept 表中的 deptno,在 Dept 表中如果有某些部门没有员工,
那么用内联接,没有员工的部门将无法显示,因此必须以 Dept 表为基准的外联接。
代码演示:外联接
SQL> SELECT e.ENAME,e.JOB,e.SAL,d.DNAME
FROM EMP e ,DEPT d
WHERE e.DEPTNO(+)=d.DEPTNO ①
代码解析:
① (+):Oracle 专用的联接符,在条件中出现在左边指右外联接,出现在右边指左外
联接。
也可以使用 SQL/92 标准的写法:
代码演示:外联接
SELECT e.ENAME,e.JOB,e.SAL,d.DNAME
FROM EMP e RIGHT OUTER JOIN DEPT d ON e.DEPTNO=d.DEPTNO
这里 RIGHT OUTER JOIN 中,关键字 OUTER 可以省略。
三、子查询和常用函数
1. 子查询
子查询在 SELECT、UPDATE、DELETE 语句内部可以出现 SELECT 语句。内部的 SELECT 语
句结果可以作为外部语句中条件子句的一部分,也可以作为外部查询的临时表。子查询的类
型有:
1. 单行子查询:不向外部返回结果,或者只返回一行结果。
2. 多行子查询:向外部返回零行、一行或者多行结果。
案例 1:查询出销售部(SALES)下面的员工姓名,工作,工资。
案例分析
该问题可以用联接查询实现,由于所需的结果信息都在 Emp 表中,可以先从 Dept 表中
查询出销售部对应的部门号,然后根据当前部门号再到 Emp 表中查询出符合该部门的员工
记录即可。从销售表中查询出的结果可以作为 Emp 表中查询的条件,SQL 语句实现如下:
代码演示:单行子查询
SQL> SELECT ENAME,JOB,SAL FROM EMP
2 WHERE DEPTNO=(SELECT DEPTNO FROM DEPT WHERE DNAME=‘SALES‘) ①
代码解析:
① 内部查询的结果作为外部查询的条件。
需要注意:
? 如果内部查询不返回任何记录,则外部条件中字段 DEPTNO 与 NULL 比较永远为假,
也就是说外部查询不返还任何结果。
? 在单行子查询中外部查询可以使用=、>、<、>=、<=、<>等比较运算符。
? 内部查询返回的结果必须与外部查询条件中的字段(DEPTNO)匹配。
? 如果内部查询返回多行结果则出现错误。
案例二:查询出 Emp 表中比任意一个销售员(“SALESMAN”)工资低的员工姓名、工作、
工资。
案例分析
销售员在 Emp 表中有很多条记录,每个人工资不相等,如果返回“比任意员工的工资
还低”的条件,返回比“最高工资还低”即可。如果用子查询做,子查询中就会返回多条记
录。用普通的关系符(>、<等)运行就会出错。这时候需要用关键字 ANY。ANY 放在比较运算符后面,表示“任意”的意思。
代码演示:ANY 子查询
SQL> SELECT ENAME,JOB,SAL FROM EMP
2 WHERE SAL<ANY (SELECT SAL FROM EMP WHERE JOB=‘SALESMAN‘) ①
代码解析:
① <any:比子查询结果中任意的值都小,也就是说,比子查询结果中最大值还小,那么
同理>any 表示比子查询结果中最小的还大。
案例 3:查询出比所有销售员的工资都高的员工姓名,工作,工资。
案例分析
ANY 可以表示任意的,但本案例中要求比所有销售员工资都高,那么就要使用另外一个
关键字 ALL。ALL 与关系操作符一起使用,表示与子查询中所有元素比较。
代码演示:ALL 子查询
SQL> SELECT ENAME,JOB,SAL FROM EMP
2 WHERE SAL>ALL (SELECT SAL FROM EMP WHERE JOB=‘SALESMAN‘) ①
代码解析:
① >ALL:比子查询结果中最大值还要大。
<ALL 表示比最小值还要小。
对于子查询还可以使用 IN 和 NOT IN 操作符进行操作。
2. Oracle 中的伪列
在 Oracle 的表的使用过程中,实际表中还有一些附加的列,称为伪列。伪列就像表中
的列一样,但是在表中并不存储。伪列只能查询,不能进行增删改操作。接下来学习两个伪
列:ROWID 和 ROWNUM。
ROWID
表中的每一行在数据文件中都有一个物理地址,ROWID 伪列返回的就是该行的物理地
址。使用 ROWID 可以快速的定位表中的某一行。ROWID 值可以唯一的标识表中的一行。由
于 ROWID 返回的是该行的物理地址,因此使用 ROWID 可以显示行是如何存储的。
代码演示:ROWID
SQL> SELECT ROWID,ENAME FROM EMP WHERE SAL>2000;
ROWNUM
在查询的结果集中,ROWNUM 为结果集中每一行标识一个行号,第一行返回 1,第二
行返回 2,以此类推。通过 ROWNUM 伪列可以限制查询结果集中返回的行数。
案例 4:查询出员工表中前 5 名员工的姓名,工作,工资。
代码演示:ROWNUM
SQL> SELECT ROWNUM,ENAME,JOB,SAL FROM EMP WHERE ROWNUM<=5;
注意:ROWNUM 与 ROWID 不同,ROWID 是插入记录时生成,ROWNUM 是查询数据时生成。
ROWID 标识的是行的物理地址。ROWNUM 标识的是查询结果中的行的次序。
案例 5:查询出工资最高的前 5 名员工的姓名、工资和工资。
案例分析
“工资最高的前 5 名”需要先降序排序,再取前 5 名,但是生成 ROWNUM 操作比排序
要早,排序时已经连同 ROWNUM 一起排序了,因此不能直接在案例 1 的语句中直接加上
Order by 就行,而是需要对排序的结果重新做二次查询,产生新的 ROWNUM 才能作为查询
的条件依据。
代码演示:ROWNUM 应用
SQL> SELECT ROWNUM,T.* FROM ①
(SELECT ENAME,JOB,SAL
FROM EMP ORDER BY SAL DESC) T ②
WHERE ROWNUM<=5
代码解析: ① T 是子查询②的别名,这里的 ROWNUM 是第二次查询后的 ROWNUM。
案例 6:查询出表 EMP 中第 5 条到第 10 条之间的记录。
案例分析
这是分页的应用。在查询条件中,如果查询条件中 ROWNUM 大于某一正整数,则不返
还任何结果。
代码演示:ROWNUM 分页
SQL> SELECT * FROM
2 (SELECT ROWNUM R,ENAME,JOB,SAL ①
3 FROM EMP WHERE ROWNUM<=10) ②
4 WHERE R>5 ③
代码解析:
① 内部查询中得到 ROWNUM 并且用别名 R 记录,供外层条件③使用。
② 内部查询的 ROWNUM,与外出的 ROWNUM 列是平等的两列。
③ 使用的 R 是内层产生的 ROWNUM,在外层看来,内层查询的 ROWNUM 是正常的一
列。
注意:SELECT ROWNUM R,ENAME,JOB,SAL FROM EMP WHERE ROWNUM>=5这样查不出任何内容
3. Oracle 函数
Oracle 数据库中主要使用两种
类型的函数:
1. 单行函数:对每一个函数应用在表的记录中时,只能输入一行结果,返回一个结果,
比如:MOD(x,y)返回 x 除以 y 的余数(x 和 y 可以是两个整数,也可以是表中的整
数列)。常用的单行函数有:
? 字符函数:对字符串操作。
? 数字函数:对数字进行计算,返回一个数字。
? 转换函数:可以将一种数据类型转换为另外一种数据类型。
? 日期函数:对日期和时间进行处理。
2. 聚合函数:聚合函数同时可以对多行数据进行操作,并返回一个结果。比如 SUM(x)
返回结果集中 x 列的总合。
字符函数
字符函数接受字符参数,这些参数可以是表中的列,也可以是一个字符串表达式。下表
列出了常用的字符函数。
数字函数
数字函数接受数字参数,参数可以来自表中的一列,也可以是一个数字表达式。
日期函数
日期函数对日期进行运算。常用的日期函数有:
1. ADD_MONTHS(d,n),在某一个日期 d 上,加上指定的月数 n,返回计算后的新日期。
d 表示日期,n 表示要加的月数
2.LAST_DAY(d),返回指定日期当月的最后一天。
3. ROUND(d[,fmt]),返回一个以 fmt 为格式的四舍五入日期值,d 是日期,fmt 是格式
模型。默认 fmt 为 DDD,即月中的某一天。
? 如果 fmt 为“YEAR”则舍入到某年的 1 月 1 日,即前半年舍去,后半年作为下
一年。
? 如果 fmt 为“MONTH”则舍入到某月的 1 日,即前月舍去,后半月作为下一
月。
? 默认为“DDD”,即月中的某一天,最靠近的天,前半天舍去,后半天作为第
二天。
? 如果 fmt 为“DAY”则舍入到最近的周的周日,即上半周舍去,下半周作为下
一周周日。
与 ROUND 对应的函数时 TRUNC(d[,fmt])对日期的操作,TRUNC 与 ROUND 非常相似,只 是不对日期进行舍入,直接截取到对应格式的第一天。
4. EXTRACT(fmt FROM d),提取日期中的特定部分。
fmt 为:YEAR、MONTH、DAY、HOUR、MINUTE、SECOND。其中 YEAR、MONTH、DAY
可以为 DATE 类型匹配,也可以与 TIMESTAMP 类型匹配;但是 HOUR、MINUTE、SECOND 必
须与 TIMESTAMP 类型匹配。
HOUR 匹配的结果中没有加上时区,因此在中国运行的结果小 8 小时。
select sysdate "date", EXTRACT(YEAR from sysdate) "year", EXTRACT(MONTH from sysdate) "month", EXTRACT(DAY from sysdate) "day", EXTRACT(HOUR from systimestamp) "hour", EXTRACT(MINUTE from systimestamp) "minute", EXTRACT(SECOND from systimestamp) "second" from dual |
转换函数
转换函数将值从一种数据类型转换为另外一种数据类型。常用的转换函数有:
1. TO_CHAR(d|n[,fmt])
把日期和数字转换为制定格式的字符串。fmt 是格式化字符串,日期的格式化字符串前
面已经学习过。
代码演示:TO_CHAR 对日期的处理
SQL> SELECT TO_CHAR(SYSDATE,‘YYYY"年"MM"月"DD"日" HH24:MI:SS‘) "date" ①
2 FROM DUAL;
date
-----------------------
2009年08月11日 12:06:00
代码解析:
① 在格式化字符串中,使用双引号对非格式化字符进行引用。
针对数字的格式化,格式化字符有:
代码演示:TO_CHAR 对数字的处理
SQL> SELECT TO_CHAR(-123123.45,‘L9.9EEEEPR‘) "date" FROM DUAL
<¥1.2E+05>
2. TO_DATE(x [,fmt])
把一个字符串以 fmt 格式转换为一个日期类型。
3. TO_NUMBER(x[,fmt])
把一个字符串以 fmt 格式转换为一个数字。fmt 格式字符参考表 3。
代码演示:TO_NUM 函数
SQL> SELECT TO_NUMBER(‘-$12,345.67‘,‘$99,999.99‘) "NUM"
2 FROM DUAL
3 /
NUM
---------------
-12345.67
其他单行函数
1. NVL(x,value)
如果 x 为空,返回 value,否则返回 x。
案例 7:对工资是 2000 元以下的员工,如果没有发奖金,每人奖金 100 元。
代码演示:NVL 函数
SQL> SELECT ENAME,JOB,SAL,NVL(COMM,100) FROM EMP WHERE SAL<2000;
2. NVL2(x,value1,value2)
如果 x 非空,返回 value1,否则返回 value2。
案例 8:对 EMP 表中工资为 2000 元以下的员工,如果没有奖金,则奖金为 200 元,如
果有奖金,则在原来的奖金基础上加 100 元。
代码演示:NVL2 函数
SQL> SELECT ENAME,JOB,SAL,NVL2(COMM,comm+100,200) "comm"
2 FROM EMP WHERE SAL<2000;
聚合函数
聚合函数同时对一组数据进行操作,返回一行结果,比如计算一组数据的总和,平均值
等。
案例 9:求本月所有员工的基本工资总和。
代码演示:SUM 函数
SQL> select sum(sal) from emp;
案例 10:求不同部门的平均工资。
代码演示:AVG 函数下的分组查询
SQL> SELECT DEPTNO,AVG(SAL) FROM EMP GROUP BY DEPTNO;
四、表空间、数据库对象
1. Oracle 数据库对象
数据库对象是数据库的组成部分,常常用 CREATE 命令进行创建,可以使用 ALTER 命令
修改,用 DROP 执行删除操作。前面已经接触过的数据库对象有表、用户等。
今天将学习更多的 Oracle 数据库对象:
? 同义词:就是给数据库对象一个别名。
? 序列:Oracle 中实现增长的对象。
? 视图:预定义的查询,作为表一样的查询使用,是一张虚拟表。
? 索引:对数据库表中的某些列进行排序,便于提高查询效率。
2. 同义词
同义词(Synonym)是数据库对象的一个别名,Oracle 可以为表、视图、序列、过程、
函数、程序包等指定一个别名。同义词有两种类型:
? 私有同义词:拥有 CREATE SYNONYM 权限的用户(包括非管理员用户)即可创建私
有同义词,创建的私有同义词只能由当前用户使用。
? 公有同义词:系统管理员可以创建公有同义词,公有同义词可以被所有用户访问。
创建同义词的语法是:
语法结构:同义词
CREATE [OR REPLACE] [PUBLIC] SYSNONYM [schema.]synonym_name
FOR [schema.]object_name
如:CREATE SYNONYM MyEmp FOR SCOTT.EMP;
语法解析:
① CREATE [OR REPLACE:]表示在创建同义词时,如果该同义词已经存在,那么就用新
创建的同义词代替旧同义词。
② PULBIC:创建公有同义词时使用的关键字,一般情况下不需要创建公有同义词。
③ Oracle 中一个用户可以创建表、视图等多种数据库对象,一个用户和该用户下的所
有数据库对象的集合称为 Schema(中文称为模式或者方案),用户名就是 Schema
名。一个数据库对象的全称是:用户名.对象名,即 schema.object_name。
如果一个用户有权限访问其他用户对象时,就可以使用全称来访问。比如:
代码演示:System 用户访问 Scott 用户的 Emp 表
SQL> SELECT ENAME,JOB,SAL FROM SCOTT.EMP WHERE SAL>2000; ①
代码解析: ① 管理员用户可以访问任何用户的数据库对象,SYSTEM 用户访问 SCOTT 用户的 EMP 表时,必须使用 SCOTT.EMP。
案例 1:创建一个用户 XiaoMei,该用户拥有 CONNECT 角色和 RESOURCE 角色。为 SCOTT
用户的 EMP 表创建同义词,并通过同义词访问该 EMP 表。
代码演示:创建同义词并访问
SQL> CONN system/[email protected];
Connected to Oracle Database 10g Enterprise Edition Release 10.2.0.3.0
Connected as system
SQL> CREATE USER XiaoMei IDENTIFIED BY XiaoMei; ①
User created
SQL> GRANT CONNECT TO XiaoMei;
Grant succeeded
SQL> GRANT RESOURCE TO XiaoMei;
Grant succeeded
SQL> GRANT CREATE SYNONYM TO XiaoMei;
Grant succeeded
SQL> CONN XiaoMei/[email protected];
Connected to Oracle Database 10g Enterprise Edition Release 10.2.0.3.0
Connected as XiaoMei
SQL> CREATE SYNONYM MyEmp FOR SCOTT.EMP; ②
Synonym created
SQL> SELECT * FROM MYEMP; ③
SELECT * FROM MYEMP
ORA-00942: 表或视图不存在
SQL> CONNECT SCOTT/[email protected]
Connected to Oracle Database 10g Enterprise Edition Release 10.2.0.3.0
Connected as SCOTT
SQL> GRANT ALL ON EMP TO XiaoMei; ④
Grant succeeded
SQL> CONNECT XiaoMei/[email protected];
Connected to Oracle Database 10g Enterprise Edition Release 10.2.0.3.0
Connected as XiaoMei
SQL> SELECT ENAME,JOB,SAL FROM MyEmp WHERE SAL>2000; ⑤
代码解析:
① 在管理员用户下创建用户 XiaoMei,对用户 XiaoMei 授予 CONNECT 和 RESOURCE 角
色。为了 XiaoMei 能够创建序列,必须授予系统权限:CREATE SYNONYM。
② 在 XiaoMei 用户下,为 SCOTT.EMP 创建私有同义词 MyEmp,同义词 MyEmp 只能在
XiaoMei 用户下使用。访问 MyEmp 就是访问 SCOTT.EMP 对象。
③ 访问 MyEmp 对象出错:对象不存在。因为 XiaoMei 如果访问 MyEmp,就相当于访
问 SCOTT.EMP 对象,那么 SCOTT 用户必须对 XiaoMei 授予相应的权限。
④ SCOTT 用户下,把 EMP 表的所有权限(增删改查)授予 XiaoMei。
⑤ 对 MyEmp 执行查询操作。MyEmp 就可以像在本地的表一样使用。
删除同义词使用的语法是:
语法结构:删除同义词
DROP [PUBLIC] SYNONYM [schema.]sysnonym_name
语法解析:
① PUBLIC:删除公共同义词。
② 同义词的删除只能被拥有同义词对象的用户或者管理员删除。
③ 此命令只能删除同义词,不能删除同义词下的源对象。
3. 序列
序列(Sequence)是用来生成连续的整数数据的对象。序列常常用来作为主键中增长列,
序列中的可以升序生成,也可以降序生成。创建序列的语法是:
语法结构:创建序列
CREATE SEQUENCE sequence_name
[START WITH num]
[INCREMENT BY increment]
[MAXVALUE num|NOMAXVALUE]
[MINVALUE num|NOMINVALUE]
[CYCLE|NOCYCLE]
[CACHE num|NOCACHE]
语法解析:
① START WITH:从某一个整数开始,升序默认值是 1,降序默认值是-1。
② INCREMENT BY:增长数。如果是正数则升序生成,如果是负数则降序生成。升序默
认值是 1,降序默认值是-1。
③ MAXVALUE:指最大值。
④ NOMAXVALUE:这是最大值的默认选项,升序的最大值是:1027,降序默认值是-1。
⑤ MINVALUE:指最小值。
⑥ NOMINVALUE:这是默认值选项,升序默认值是 1,降序默认值是-1026。
⑦ CYCLE:表示如果升序达到最大值后,从最小值重新开始;如果是降序序列,达到最
小值后,从最大值重新开始。
⑧ NOCYCLE:表示不重新开始,序列升序达到最大值、降序达到最小值后就报错。默
认 NOCYCLE。
⑨ CACHE:使用 CACHE 选项时,该序列会根据序列规则预生成一组序列号。保留在内
存中,当使用下一个序列号时,可以更快的响应。当内存中的序列号用完时,系统
再生成一组新的序列号,并保存在缓存中,这样可以提高生成序列号的效率。Oracle
默认会生产 20 个序列号。
⑩ NOCACHE:不预先在内存中生成序列号
案例 2:创建一个从 1 开始,默认最大值,每次增长 1 的序列,要求 NOCYCLE,缓存中
有 30 个预先分配好的序列号。
代码演示:生成序列号
SQL> CREATE SEQUENCE MYSEQ
MINVALUE 1
START WITH 1
NOMAXVALUE
INCREMENT BY 1
NOCYCLE
CACHE 30
序列创建之后,可以通过序列对象的 CURRVAL 和 NEXTVAL 两个“伪列”分别访问该序
列的当前值和下一个值。
代码演示:序列使用
SQL> SELECT MYSEQ.NEXTVAL FROM DUAL;
NEXTVAL
----------
1
SQL> SELECT MYSEQ.NEXTVAL FROM DUAL;
NEXTVAL
----------
2
SQL> SELECT MYSEQ.CURRVAL FROM DUAL;
CURRVAL
----------
2
使用 ALTER SEQUENCE 可以修改序列,在修改序列时有如下限制:
1. 不能修改序列的初始值。
2. 最小值不能大于当前值。
3. 最大值不能小于当前值。
使用 DROP SEQUENCE 命令可以删除一个序列对象。
代码演示:序列修改和删除
SQL> ALTER SEQUENCE MYSEQ
MAXVALUE 10000
MINVALUE -300
SEQUENCE ALTERED
SQL> DROP SEQUENCE MYSEQ;
SEQUENCE DROPPED
4. 视图
视图(View)实际上是一张或者多张表上的预定义查询,这些表称为基表。从视图中
查询信息与从表中查询信息的方法完全相同。只需要简单的 SELECT…FROM 即可。
视图具有以下优点:
1. 可以限制用户只能通过视图检索数据。这样就可以对最终用户屏蔽建表时底层的基
表。
2. 可以将复杂的查询保存为视图。可以对最终用户屏蔽一定的复杂性。
3. 限制某个视图只能访问基表中的部分列或者部分行的特定数据。这样可以实现一定
的安全性。
4. 从多张基表中按一定的业务逻辑抽出用户关心的部分,形成一张虚拟表。
语法结构:创建视图
CREATE [OR REPLACE] [{FORCE|NOFORCE}] VIEW view_name
AS
SELECT查询
[WITH READ ONLY CONSTRAINT]
语法解析:
1. OR REPLACE:如果视图已经存在,则替换旧视图。
2. FORCE:即使基表不存在,也可以创建该视图,但是该视图不能正常使用,当基表
创建成功后,视图才能正常使用。
3. NOFORCE:如果基表不存在,无法创建视图,该项是默认选项。
4. WITH READ ONLY:默认可以通过视图对基表执行增删改操作,但是有很多在基表上
的限制(比如:基表中某列不能为空,但是该列没有出现在视图中,则不能通过视
图执行 insert 操作),WITH READ ONLY 说明视图是只读视图,不能通过该视图进行
增删改操作。现实开发中,基本上不通过视图对表中的数据进行增删改操作。
案例 3:基于 EMP 表和 DEPT 表创建视图
代码演示:视图
SQL> CREATE OR REPLACE VIEW EMPDETAIL
AS
SELECT EMPNO,ENAME,JOB,HIREDATE,EMP.DEPTNO,DNAME
FROM EMP JOIN DEPT ON EMP.DEPTNO=DEPT.DEPTNO
WITH READ ONLY
代码解析:
① 对视图可以像表一样进行查询。该视图中隐藏了员工的工资。
删除视图可以使用“DROP VIEW 视图名称”,删除视图不会影响基表的数据。
5. 索引
数据库中索引(Index)的概念与目录的概念非常类似。如果某列出现在查询的条件中,
而该列的数据是无序的,查询时只能从第一行开始一行一行的匹配。创建索引就是对某些特
定列中的数据排序,生成独立的索引表。在某列上创建索引后,如果该列出现在查询条件中,
Oracle 会自动的引用该索引,先从索引表中查询出符合条件记录的 ROWID,由于 ROWID 是
记录的物理地址,因此可以根据 ROWID 快速的定位到具体的记录,表中的数据非常多时,
引用索引带来的查询效率非常可观。
如果表中的某些字段经常被查询并作为查询的条件出现时,就应该考
虑为该列创建索引。
当从很多行的表中查询少数行时,也要考虑创建索引。有一条基本的准则是:当任何单个查询要检索的行少于或者等于整个表行数的 10%时,索引就非常有用。
Oracle 数据库会为表的主键和包含唯一约束的列自动创建索引。索引可以提高查询的效
率,但是在数据增删改时需要更新索引,因此索引对增删改时会有负面影响。
语法结构:创建索引
CREATE [UNIQUE] INDEX index_name ON
table_name(column_name[,column_name…])
语法解析:
1. UNIQUE:指定索引列上的值必须是唯一的。称为唯一索引。
2. index_name:指定索引名。
3. tabl_name:指定要为哪个表创建索引。
4. column_name:指定要对哪个列创建索引。我们也可以对多列创建索引;这种索引
称为组合索引。
案例 4:为 EMP 表的 ENAME 列创建创建唯一索引,为 EMP 表的工资列创建普通索引,
把 JOB 列先变为小写再创建索引。
代码演示:创建索引
SQL> CREATE UNIQUE INDEX UQ_ENAME_IDX ON EMP(ENAME); ①
Index created
SQL> CREATE INDEX IDX_SAL ON EMP(SAL); ②
Index created
SQL> CREATE INDEX IDX_JOB_LOWER ON EMP(LOWER(JOB)); ③
Index created
代码解析:
① 为 SCOTT.EMP 表的 ENAME 列创建唯一索引。
② 为 SCOTT.EMP 表的 SAL 列创建索引。
③ 在查询中可能经常使用 job 的小写作为条件的表达式,因此创建索引时,可以先对
JOB 列中的所有值转换为小写后创建索引,而这时需要使用 lower 函数,这种索引
称为基于函数的索引。
在 select 语句查询时,Oracle 系统会自动为查询条件上的列应用索引。索引就是对某一
列进行排序,因此在索引列上,重复值越少,索引的效果越明显。
Oracle 可以为一些列值重复非常多且值有限的列(比如性别列)上创建位图索引。关于
Oracle 更多的索引类型(比如反向键索引等),请参考 Oracle 官方文档。
6. 表空间
在数据库系统中,存储空间是较为重要的资源,合理利用空间,不但能节省空间,还可
以提高系统的效率和工作性能。Oracle 可以存放海量数据,所有数据都在数据文件中存储。
而数据文件大小受操作系统限制,并且过大的数据文件对数据的存取性能影响非常大。同时
Oracle 是跨平台的数据库,Oracle 数据可以轻松的在不同平台上移植,那么如何才能提供统
一存取格式的大容量呢?Oracle 采用表空间来解决。
表空间只是一个逻辑概念,若干操作系统文件(文件可以不是很大)可以组成一个表空
间。表空间统一管理空间中的数据文件,一个数据文件只能属于一个表空间。一个数据库空
间由若干个表空间组成。如图所示:
Oracle 中所有的数据(包括系统数据),全部保存在表空间中,常见的表空间有:
? 系统表空间:存放系统数据,系统表空间在数据库创建时创建。表空间名称为
SYSTEM。存放数据字典和视图以及数据库结构等重要系统数据信息,在运行时如
果 SYSTEM 空间不足,对数据库影响会比较大,虽然在系统运行过程中可以通过命
令扩充空间,但还是会影响数据库的性能,因此有必要在创建数据库时适当的把数
据文件设置大一些。
? TMEP 表空间:临时表空间,安装数据库时创建,可以在运行时通过命令增大临时
表空间。临时表空间的重要作用是数据排序。比如当用户执行了诸如 Order by 等
命令后,服务器需要对所选取数据进行排序,如果数据很大,内存的排序区可能装
不下太大数据,就需要把一些中间的排序结果写在硬盘的临时表空间中。
? 用户表自定义空间:用户可以通过 CREATE TABLESPACE 命令创建表空间。
创建表空间需要考虑数据库对分区(Extent,一个 Oracle 分区是数据库文件中一段连续 的空间,Oracle 分区是 Oracle 管理中最小的单位)的管理,比如当一个表创建后先申请一个 分区,在 Insert 执行过程中,如果分区数据已满,需要重新申请另外的分区。如果一个数据 库中的分区大小不一,创建表空间时需要考虑一系列问题。因此在 Oracle8i 之后,创建表空间都推荐使用“本地管理表空间”,这种表空间中的分区是一个固定大小的值,创建表空间 的语法是:
语法结构:创建表空间
CREATE TABLESPACE 空间名称
DATAFILE ‘文件名1‘ SIZE 数字M
[,‘文件名2‘ SIZE 数字….]
EXTENT MANAGEMENT LOCAL
UNIFORM SIZE 数字M
语法解析:
1. 文件名包括完整路径和文件名,每个数据文件定义了文件的初始大小,初始大小一
般以“M”为单位。一个表空间中可以有多个数据文件。
2. EXTENT MANAGEMENT LOCAL 指明表空间类型是:本地管理表空间。本地管理表空
间要求 Oracle 中的数据分区(Extent)大小统一。
3. UNIFORM SIZE:指定每个分区的统一大小。
案例 5:创建一个表空间,包含两个数据文件大小分别是 10MB,5MB,要求 extent 的
大小统一为 1M。
代码演示:创建表空间
CREATE TABLESPACE myspace DATAFILE ‘E://A.ORA‘ SIZE 10M, ‘E://B.ORA‘ SIZE 5M EXTENT MANAGEMENT LOCAL UNIFORM SIZE 1M |
然后打开对应盘符查看
必须是管理员用户才能创建表空间,当表空间的空间不足时可以使用 ALTER TABLESPACE
命令向表空间中追加数据文件扩充表空间。
代码演示:扩充表空间
ALTER TABLESPACE myspace ADD DATAFILE ‘E:/C.ORA‘ SIZE 10M |
表空间可以在不使用时删除,使用 DROP TABLESPACE 命令。
DROP TABLESPACE myspace |
注意该命令并不能删除创建的.ORA文件
数据库的所有数据全部在某一表空间中存放,在创建用户时,可以为用户指定某一表空
间,那么该用户下的所有数据库对象(比如表)默认都存储在该空间中。
代码演示:为某一用户指定默认表空间
SQL> CREATE USER ACONG IDENTIFIED BY ACONG
DEFAULT TABLESPACE MYSPACE
在创建表时,表中数据存放在用户的默认表空间中,也可以通过 tablespace 子句为表指
定表中数据存放在其他表空间中。
代码演示:为表指定表空间
CREATE TABLE SCORES ( ID NUMBER , TERM VARCHAR2(2), STUID VARCHAR2(7) NOT NULL, EXAMNO VARCHAR2(7) NOT NULL, WRITTENSCORE NUMBER(4,1) NOT NULL, LABSCORE NUMBER(4,1) NOT NULL ) TABLESPACE myspace |
创建索引时也可以为索引指定表空间。
代码演示:为索引指定表空间
CREATE INDEX UQ_ID ON SCORES(ID) TABLESPACE myspace |
表和索引一旦创建,表空间无法修改。
五、Oracle存储过程
1.定义
所谓存储过程(Stored
Procedure),就是一组用于完成特定数据库功能的SQL语句集,该SQL语句集经过编译后存储在数据库系统中。在使用时候,用户通过指定已经定义的存储过程名字并给出相应的存储过程参数来调用并执行它,从而完成一个或一系列的数据库操作。
2.存储过程的创建
Oracle存储过程包含三部分:过程声明,执行过程部分,存储过程异常。
(1)无参存储过程语法
create or replace procedure NoParPro as //声明 ; begin // 执行 ; exception//存储过程异常 ; end; |
(2)带参存储过程实例
create or replace procedure queryempname(sfindno emp.empno%type) as sName emp.ename%type; sjob emp.job%type; begin .... exception .... end; |
(3)带参数存储过程含赋值方式
create or replace procedure runbyparmeters (isal in emp.sal%type, sname out varchar, sjob in out varchar) as icount number; begin select count(*) into icount from emp where sal>isal and job=sjob; if icount=1 then .... else .... end if; exception when too_many_rows then DBMS_OUTPUT.PUT_LINE(‘返回值多于1行‘); when others then DBMS_OUTPUT.PUT_LINE(‘在RUNBYPARMETERS过程中出错!‘); end; |
其中参数IN表示输入参数,是参数的默认模式。
OUT表示返回值参数,类型可以使用任意Oracle中的合法类型。
OUT模式定义的参数只能在过程体内部赋值,表示该参数可以将某个值传递回调用他的过程
IN OUT表示该参数可以向该过程中传递值,也可以将某个值传出去。
(4)存储过程中游标定义使用
as //定义(游标一个可以遍历的结果集) CURSOR cur_1 IS SELECT area_code,CMCODE,SUM(rmb_amt)/10000 rmb_amt_sn, SUM(usd_amt)/10000 usd_amt_sn FROM BGD_AREA_CM_M_BASE_T WHERE ym >= vs_ym_sn_beg AND ym <= vs_ym_sn_end GROUP BY area_code,CMCODE;
begin //执行(常用For语句遍历游标) FOR rec IN cur_1 LOOP UPDATE xxxxxxxxxxx_T SET rmb_amt_sn = rec.rmb_amt_sn,usd_amt_sn = rec.usd_amt_sn WHERE area_code = rec.area_code AND CMCODE = rec.CMCODE AND ym = is_ym; END LOOP; |
(5)游标的定义
--显示cursor的处理 declare ---声明cursor,创建和命名一个sql工作区 cursor cursor_name is select real_name from account_hcz; v_realname varchar2(20); begin open cursor_name;---打开cursor,执行sql语句产生的结果集 fetch cursor_name into v_realname;--提取cursor,提取结果集中的记录 dbms_output.put_line(v_realname); close cursor_name;--关闭cursor end; |
3、在Oracle中对存储过程的调用
(1)过程调用方式一
declare realsal emp.sal%type; realname varchar(40); realjob varchar(40); begin //过程调用开始 realsal:=1100; realname:=‘‘; realjob:=‘CLERK‘; runbyparmeters(realsal,realname,realjob);--必须按顺序 DBMS_OUTPUT.PUT_LINE(REALNAME||‘ ‘||REALJOB); END; //过程调用结束 |
(2)过程调用方式二
declare realsal emp.sal%type; realname varchar(40); realjob varchar(40); begin //过程调用开始 realsal:=1100; realname:=‘‘; realjob:=‘CLERK‘; --指定值对应变量顺序可变 runbyparmeters(sname=>realname,isal=>realsal,sjob=>realjob); DBMS_OUTPUT.PUT_LINE(REALNAME||‘ ‘||REALJOB); END; //过程调用结束 |
(3)过程调用方式三(SQL命令行方式下)
1、SQL>exec proc_emp(‘参数1‘,‘参数2‘);//无返回值过程调用 2、SQL>var vsal number SQL> exec proc_emp (‘参数1‘,:vsal);// 有返回值过程调用 或者:call proc_emp (‘参数1‘,:vsal);// 有返回值过程调用
|
六、PL/SQL 程序设计
1.PL/SQL 简介
Oracle PL/SQL 语言(Procedural Language/SQL)是结合了结构化 查询与 Oracle 自身过程控制为一体的强大语言,PL/SQL 不但支持更多的数据类型,拥有自 身的变量声明、赋值语句,而且还有条件、循环等流程控制语句。过程控制结构与 SQL 数 据处理能力无缝的结合形成了强大的编程语言,可以创建过程和函数以及程序包。
PL/SQL 是一种块结构的语言,它将一组语句放在一个块中,一次性发送给服务器,PL/SQL 引擎分析收到 PL/SQL 语句块中的内容,把其中的过程控制语句由 PL/SQL 引擎自身去执行, 把 PL/SQL 块中的 SQL 语句交给服务器的 SQL 语句执行器执行。如图所示:
PL/SQL 块发送给服务器后,先被编译然后执行,对于有名称的 PL/SQL 块(如子程序) 可以单独编译,永久的存储在数据库中,随时准备执行。PL/SQL 的优点还有:
支持 SQL
SQL 是访问数据库的标准语言,通过 SQL 命令,用户可以操纵数据库中的数据。PL/SQL
支持所有的 SQL 数据操纵命令、游标控制命令、事务控制命令、SQL 函数、运算符和伪列。
同时 PL/SQL 和 SQL 语言紧密集成,PL/SQL 支持所有的 SQL 数据类型和 NULL 值。
支持面向对象编程
PL/SQL 支持面向对象的编程,在 PL/SQL 中可以创建类型,可以对类型进行继承,可以
在子程序中重载方法等。
更好的性能
SQL 是非过程语言,只能一条一条执行,而 PL/SQL 把一个 PL/SQL 块统一进行编译后执
行,同时还可以把编译好的 PL/SQL 块存储起来,以备重用,减少了应用程序和服务器之间
的通信时间,PL/SQL 是快速而高效的。
可移植性
使用 PL/SQL 编写的应用程序,可以移植到任何操作系统平台上的 Oracle 服务器,同时
还可以编写可移植程序库,在不同环境中重用。
安全性
可以通过存储过程对客户机和服务器之间的应用程序逻辑进行分隔,这样可以限制对
Oracle 数据库的访问,数据库还可以授权和撤销其他用户访问的能力。
2.PL/SQL 块
PL/SQL 是一种块结构的语言,一个 PL/SQL 程序包含了一个或者多个逻辑块,逻辑块中
可以声明变量,变量在使用之前必须先声明。除了正常的执行程序外,PL/SQL 还提供了专
门的异常处理部分进行异常处理。每个逻辑块分为三个部分,语法是:
语法结构:PL/SQL 块的语法
[DECLARE
--declaration statements] ①
BEGIN
--executable statements ②
[EXCEPTION
--exception statements] ③
END;
语法解析:
① 声明部分:声明部分包含了变量和常量的定义。这个部分由关键字 DECLARE 开始,
如果不声明变量或者常量,可以省略这部分。
② 执行部分:执行部分是 PL/SQL 块的指令部分,由关键字 BEGIN 开始,关键字 END
结尾。所有的可执行 PL/SQL 语句都放在这一部分,该部分执行命令并操作变量。
其他的 PL/SQL 块可以作为子块嵌套在该部分。PL/SQL 块的执行部分是必选的。注
意 END 关键字后面用分号结尾。
③ 异常处理部分:该部分是可选的,该部分用 EXCEPTION 关键字把可执行部分分成两
个小部分,之前的程序是正常运行的程序,一旦出现异常就跳转到异常部分执行。
PL/SQL 是一种编程语言,与 Java 和 C#一样,除了有自身独有的数据类型、变量声明和赋
值以及流程控制语句外,PL/SQL 还有自身的语言特性:
PL/SQL 对大小写不敏感,为了良好的程序风格,开发团队都会选择一个合适的编码标准。
比如有的团队规定:关键字全部大些,其余的部分小写。
PL/SQL 块中的每一条语句都必须以分号结束,SQL 语句可以是多行的,但分号表示该语
句结束。一行中可以有多条 SQL 语句,他们之间以分号分隔,但是不推荐一行中写多条语
句。
PL/SQL 中的特殊符号说明:
变量声明
PL/SQL 支持 SQL 中的数据类型,PL/SQL 中正常支持 NUMBER,VARCHAR2,DATE 等 Oracle
SQL 数据类型。声明变量必须指明变量的数据类型,也可以声明变量时对变量初始化,变量
声明必须在声明部分。声明变量的语法是:
语法格式:声明变量
变量名 数据类型[ :=初始值]
语法解析: 数据类型如果需要长度,可以用括号指明长度,比如:varchar2(20)。
代码演示:声明变量
DECLARE sname VARCHAR2(20) :=‘jerry‘; ① BEGIN sname:=sname||‘ and tom‘; ② dbms_output.put_line(sname); ③ END; |
代码解析:
① 声明一个变量 sname,初始化值是“jerry”。字符串用单引号,如果字符串中出现单
引号可以使用两个单引号(’’)来表示,即单引号同时也具有转义的作用。
② 对变量 sname 重新赋值,赋值运算符是“:=”。
③ dbms_output.put_line 是输出语句,可以把一个变量的值输出,在 SQL*Plus 中输出
数据时,可能没有结果显示,可以使用命令:set serveroutput on 设置输出到 SQL*Plus
控制台上。
对变量赋值还可以使用 SELECT…INTO 语句从数据库中查询数据对变量进行赋值。但是
查询的结果只能是一行记录,不能是零行或者多行记录。
代码演示:变量赋值
DECLARE sname VARCHAR2(20) DEFAULT ‘jerry‘; ① BEGIN SELECT ename INTO sname FROM emp WHERE empno=7934; ② dbms_output.put_line(sname); END; |
代码解析:
① 变量初始化时,可以使用 DEFAULT 关键字对变量进行初始化。
② 使用 select…into 语句对变量 sname 赋值,要求查询的结果必须是一行,不能是多
行或者没有记录。
声明常量
常量在声明时赋予初值,并且在运行时不允许重新赋值。使用 CONSTANT 关键字声明常
量。
代码演示:声明常量
DECLARE pi CONSTANT number :=3.14; --圆周率长值① r number DEFAULT 3; --圆的半径默认值3 ② area number; --面积。 BEGIN area:=pi*r*r; --计算面积 dbms_output.put_line(area); --输出圆的面积 END; |
代码解析:
① 声明常量时使用关键字 CONSTANT,常量初值可以使用赋值运算符(:=)赋值,也
可以使用 DEFAULT 关键字赋值。
在 SQL*Plus 中还可以声明 Session(会话,也就是一个客户端从连接到退出的过程称为
当前用户的会话。)全局级变量,该变量在整个会话过程中均起作用,类似的这种变量称为
宿主变量。宿主变量在 PL/SQL 引用时要用“:变量名”引用。
代码演示:宿主常量
SQL> var emp_name varchar(30); ①
SQL> BEGIN
2 SELECT ename INTO :emp_name FROM emp WHERE empno=7499; ②
3 END;
4 /
PL/SQL procedure successfully completed
emp_name
---------
ALLEN
SQL> print emp_name; ③
emp_name
---------
ALLEN
代码解析:
① 可以使用 var 声明宿主变量。
② PL/SQL 中访问宿主变量时要在变量前加“:”。
③ 在 SQL*Plus 中,使用 print 可以输出变量中的结果。
3. PL/SQL 数据类型
标量数据类型
标量数据类型的变量只有一个值,且内部没有分量。标量数据类型包括数字型,字符型, 日期型和布尔型。这些类型有的是 Oracle SQL 中定义的数据类型,有的是 PL/SQL 自身附加 的数据类型。字符型和数字型又有子类型,子类型只与限定的范围有关,比如 NUMBER 类 型可以表示整数,也可以表示小数,而其子类型 POSITIVE 只表示正整数。
属性数据类型
当声明一个变量的值是数据库中的一行或者是数据库中某列时,可以直接使用属性类型
来声明。Oracle 中存在两种属性类型:%TYPE 和%ROWTYPE。
? % ROWTYPE
引用数据库表中的一行作为数据类型,即 RECORD 类型(记录类型),是 PL/SQL 附加的
数据类型。表示一条记录,就相当于 C#中的一个对象。可以使用“.”来访问记录中的属性。
代码演示:
SQL> DECLARE
2 myemp EMP%ROWTYPE; ①
3 BEGIN
4 SELECT * INTO myemp FROM emp WHERE empno=7934; ②
5 dbms_output.put_line(myemp.ename); ③
6 END;
7 /
MILLER
PL/SQL procedure successfully completed
代码解析:
① 声明一个 myemp 对象,该对象表示 EMP 表中的一行。
② 从 EMP 表中查询一条记录放入 myemp 对象中。
③ 访问该对象的属性可以使用“.”。
? %TYPE
引用某个变量或者数据库的列的类型作为某变量的数据类型。
代码演示:%TYPE 应用
SQL> DECLARE
2 sal emp.sal%TYPE; ①
3 mysal number(4):=3000;
4 totalsal mysal%TYPE; ②
5 BEGIN
6 SELECT SAL INTO sal FROM emp WHERE empno=7934;
7 totalsal:=sal+mysal;
8 dbms_output.put_line(totalsal);
9 END;
10 /
4300
PL/SQL procedure successfully completed
代码解析:
① 定义变量 sal 为 emp 表中 sal 列的类型。
② 定义 totalsal 是变量 mysal 的类型。
%TYPE 可以引用表中的某列作的类型为变量的数据类型,也可以引用某变量的类型作为
新变量的数据类型。
4.PL/SQL 条件控制和循环控制
PL/SQL 程序可通过条件或循环结构来控制命令执行的流程。PL/SQL 提供了丰富的流程
控制语句,与 C#一样也有三种控制结构:
? 顺序结构
? 条件结构
? 循环结构
条件控制
PL/SQL 中关于条件控制的关键字有 IF-THEN、IF-THEN-ELSE、IF-THEN-ELSIF 和多分枝条件 CASE。
? IF-THEN
该结构先判断一个条件是否为 TRUE,条件成立则执行对应的语句块,
具体语法是:
IF 条件 THEN
--条件结构体
END IF;
说明:
① 用 IF 关键字开始,END IF 关键字结束,注意 END IF 后面有一个分号。
② 条件部分可以不使用括号,但是必须以关键字 THEN 来标识条件结束,如果条件成
立,则执行 THEN 后到对应 END IF 之间的语句块内容。如果条件不成立,则不执行
条件语句块的内容。
④ PL/SQL 中关键字 THEN 到 END IF 之间的内容是条件结构体内容。
⑤ 条件可以使用关系运算符合逻辑运算符。
案例 1:查询 JAMES 的工资,如果大于 900 元,则发奖金 800 元。
代码演示:IF-THEN 应用
DECLARE
newSal emp.sal % TYPE;
BEGIN
SELECT sal INTO newSal FROM emp
WHERE ename=‘JAMES‘;
IF newSal>900 THEN ①
UPDATE emp
SET comm=800
WHERE ename=‘JAMES‘;
END IF;
COMMIT ; ②
END;
代码解析:
① 先判断条件,如果条件为 TRUE,则执行条件结构体内部的内容。
② 在 PL/SQL 块中可以使用事务控制语句,该 COMMIT 同时也能把 PL/SQL 块外没有提
交的数据一并提交,使用时需要注意。
? IF-THEN-ELSE
语法格式:IF-THEN-ELSE
IF 条件 THEN
--条件成立结构体
ELSE
--条件不成立结构体
END IF;
语法解析:
把 ELSE 与 IF-THEN 连在一起使用,如果 IF 条件不成立则执行就会执行 ELSE 部分的语句。
案例 2:查询 JAMES 的工资,如果大于 900 元,则发奖金 800 元,否则发奖金 400 元。
DECLARE newSal emp.sal % TYPE; BEGIN SELECT sal INTO newSal FROM emp WHERE ename=‘JAMES‘; IF newSal>900 THEN UPDATE emp SET comm=800 WHERE ename=‘JAMES‘; Else UPDATE emp SET comm=400 WHERE ename=‘JAMES‘; END IF; COMMIT ; END; |
? IF-THEN-ELSIF
语法格式:IF-THEN-ELSIF
IF 条件 1 THEN
--条件 1 成立结构体
ELSIF 条件 2 THEN
--条件 2 成立结构体
ELSE
--以上条件都不成立结构体
END IF;
语法解析:
PL/SQL 中的再次条件判断中使用关键字 ELSIF。
案例 3:查询 JAMES 的工资,如果大于 1500 元,则发放奖金 100 元,如果工作大于 900
元,则发奖金 800 元,否则发奖金 400 元。
代码演示:
DECLARE newSal emp.sal % TYPE; BEGIN SELECT sal INTO newSal FROM emp WHERE ename=‘JAMES‘; IF newSal>1500 THEN UPDATE emp SET comm=100 WHERE ename=‘JAMES‘; ELSIF newSal>900 THEN UPDATE emp SET comm=800 WHERE ename=‘JAMES‘; Else UPDATE emp SET comm=400 WHERE ename=‘JAMES‘; END IF; COMMIT ; END;
|
? CASE
CASE 是一种选择结构的控制语句,可以根据条件从多个执行分支中选择相应的执行动
作。也可以作为表达式使用,返回一个值。语法是:
语法格式:CASE
CASE [selector]
WHEN 表达式 1 THEN 语句序列 1;
WHEN 表达式 2 THEN 语句序列 2;
WHEN 表达式 3 THEN 语句序列 3;
……
[ELSE 语句序列 N];
END CASE;
语法解析:
如果存在选择器 selector,选择器 selector 与 WHEN 后面的表达式匹配,匹配成功就执
行 THEN 后面的语句。如果所有表达式都与 selector 不匹配,则执行 ELSE 后面的语句。
案例 4:输入一个字母 A、B、C 分别输出对应的级别信息。
代码演示:CASE 中存在 selector,不返回值
DECLARE
v_grade CHAR(1):=UPPER(‘&p_grade‘); ①
BEGIN
CASE v_grade ②
WHEN ‘A‘ THEN
dbms_output.put_line(‘Excellent‘);
WHEN ‘B‘ THEN
dbms_output.put_line(‘Very Good‘);
WHEN ‘C‘ THEN
dbms_output.put_line(‘Good‘);
ELSE
dbms_output.put_line(‘No such grade‘);
END CASE;
END;
代码解析:
① & grade 表示在运行时由键盘输入字符串到 grade 变量中。
② v_grade 分别于 WHEN 后面的值匹配,如果成功就执行 WHEN 后的程序序列。
CASE 语句还可以作为表达式使用,返回一个值。
代码演示:CASE 中存在 selector,作为表达式使用
DECLARE
v_grade CHAR(1):=UPPER(‘&grade‘);
p_grade VARCHAR(20) ;
BEGIN
p_grade := ①
CASE v_grade
WHEN ‘A‘ THEN
‘Excellent‘
WHEN ‘B‘ THEN
‘Very Good‘
WHEN ‘C‘ THEN
‘Good‘
ELSE
‘No such grade‘
END;
dbms_output.put_line(‘Grade:‘ ||v_grade||‘,the result is ‘||p_grade);
END;
代码解析:
① CASE 语句可以返回一个结果给变量 p_grade
PL/SQL 还提供了搜索 CASE 语句。也就是说,不使用 CASE 中的选择器,直接在 WHEN
后面判断条件,第一个条件为真时,执行对应 THEN 后面的语句序列。
代码演示:搜索 CASE
DECLARE
v_grade CHAR(1):=UPPER(‘&grade‘);
p_grade VARCHAR(20) ;
BEGIN
p_grade :=
CASE
WHEN v_grade=‘A‘ THEN
‘Excellent‘
WHEN v_grade=‘B‘ THEN
‘Very Good‘
WHEN v_grade=‘C‘ THEN
‘Good‘
ELSE
‘No such grade‘
END;
dbms_output.put_line(‘Grade:‘ ||v_grade||‘,the result is ‘||p_grade);
END;
循环结构
PL/SQL 提供了丰富的循环结构来重复执行一些列语句。Oracle 提供的循环类型有:
1. 无条件循环 LOOP-END LOOP 语句
2. WHILE 循环语句
3. FOR 循环语句
在上面的三类循环中 EXIT 用来强制结束循环,相当于 C#循环中的 break。
LOOP 循环
LOOP 循环是最简单的循环,也称为无限循环,LOOP 和 END LOOP 是关键字。
语法格式:LOOP 循环
LOOP
--循环体
END LOOP;
语法格式:
1. 循环体在 LOOP 和 END LOOP 之间,在每个 LOOP 循环体中,首先执行循环体中的语
句序列,执行完后再重新开始执行。
2. 在 LOOP 循环中可以使用 EXIT 或者[EXIT WHEN 条件]的形式终止循环。否则该循环
就是死循环。
案例 5:执行 1+2+3+…+100 的值
代码演示:LOOP 循环
DECLARE
counter number(3):=0;
sumResult number:=0;
BEGIN
LOOP
counter := counter+1;
sumResult := sumResult+counter;
IF counter>=100 THEN ①
EXIT;
END IF;
-- EXIT WHEN counter>=100; ②
END LOOP;
dbms_output.put_line(‘result is :‘||to_char(sumResult));
END;
代码解析:
① LOOP 循环中可以使用 IF 结构嵌套 EXIT 关键字退出循环
② 注释行,该行可以代替①中的循环结构,WHEN 后面的条件成立时跳出循环。
WHILE 循环
语法格式:WHILE
WHILE 条件 LOOP
--循环体
END LOOP;
案例 6:WHILE 循环
代码演示:WHILE 循环
DECLARE
counter number(3):=0;
sumResult number:=0;
BEGIN
WHILE counter<100 LOOP
counter := counter+1;
sumResult := sumResult+counter;
END LOOP;
dbms_output.put_line(‘result is :‘||sumResult);
END;
FOR 循环
FOR 循环需要预先确定的循环次数,可通过给循环变量指定下限和上限来确定循环运行
的次数,然后循环变量在每次循环中递增(或者递减)。FOR 循环的语法是:
语法格式:FOR 循环
FOR 循环变量 IN [REVERSE] 循环下限..循环上限 LOOP LOOP
--循环体
END LOOP;
语法解析:
循环变量:该变量的值每次循环根据上下限的 REVERSE 关键字进行加 1 或者减 1。
REVERSE:指明循环从上限向下限依次循环。
案例 7:FOR 循环
代码演示:FOR 循环
DECLARE
counter number(3):=0;
sumResult number:=0;
BEGIN
FOR counter IN 1..100 LOOP
sumResult := sumResult+counter;
END LOOP;
dbms_output.put_line(‘result is :‘||sumResult);
END;
顺序结构
在程序顺序结构中有两个特殊的语句。GOTO 和 NULL
GOTO 语句
GOTO 语句将无条件的跳转到标签指定的语句去执行。标签是用双尖括号括起来的标示
符,在 PL/SQL 块中必须具有唯一的名称,标签后必须紧跟可执行语句或者 PL/SQL 块。
GOTO 不能跳转到 IF 语句、CASE 语句、LOOP 语句、或者子块中。
NULL 语句
NULL 语句什么都不做,只是将控制权转到下一行语句。NULL 语句是可执行语句。NULL
语句在 IF 或者其他语句语法要求至少需要一条可执行语句,但又不需要具体操作的地
方。比如 GOTO 的目标地方不需要执行任何语句时。
案例 8:GOGO 和 NULL
代码演示:GOTO 和 NULL
DECLARE
sumsal emp.sal%TYPE;
BEGIN
SELECT SUM(sal) INTO sumsal FROM EMP;
IF sumsal>20000 THEN
GOTO first_label; ①
ELSE
GOTO second_label; ②
END IF;
<<first_label>> ③
dbms_output.put_line(‘ABOVE 20000:‘ || sumsal);
<<second_label>> ④
NULL;
END;
代码解析:
① 跳转到程序 first_label 位置,就是②的位置,first_label 是一个标签,用两个尖括号
包含。
② 无条件跳转到 sedond_label 位置,就是④的位置。④处不执行任何内容,因此是一
个 NULL 语句。
在 PL/SQL 中,各种循环之间可以相互嵌套
5. PL/SQL 中动态执行 SQL 语句
在 PL/SQL 程序开发中,可以使用 DML 语句和事务控制语句,但是还有很多语句(比如
DDL 语句)不能直接在 PL/SQL 中执行。这些语句可以使用动态 SQL 来实现。
PL/SQL 块先编译然后再执行,动态 SQL 语句在编译时不能确定,只有在程序执行时把
SQL 语句作为字符串的形式由动态 SQL 命令来执行。在编译阶段 SQL 语句作为字符串存在,
程序不会对字符串中的内容进行编译,在运行阶段再对字符串中的 SQL 语句进行编译和执
行,动态 SQL 的语法是:
语法格式:动态 SQL
EXECUTE IMMEDIATE 动态语句字符串
[INTO 变量列表]
[USING 参数列表]
语法解析:
如果动态语句是 SELECT 语句,可以把查询的结果保存到 INTO 后面的变量中。如果动态
语句中存在参数,USING 为语句中的参数传值。
动态 SQL 中的参数格式是:[:参数名],参数在运行时需要使用 USING 传值。
案例 9:动态 SQL
代码演示:动态 SQL
DECLARE
sql_stmt VARCHAR2(200); --动态SQL语句
emp_id NUMBER(4) := 7566;
salary NUMBER(7,2);
dept_id NUMBER(2) := 90;
dept_name VARCHAR2(14) := ‘PERSONNEL‘;
location VARCHAR2(13) := ‘DALLAS‘;
emp_rec emp%ROWTYPE;
BEGIN
--无子句的execute immediate
EXECUTE IMMEDIATE ‘CREATE TABLE bonus1 (id NUMBER, amt NUMBER)‘; ①
----using子句的execute immediate
sql_stmt := ‘INSERT INTO dept VALUES (:1, :2, :3)‘;
EXECUTE IMMEDIATE sql_stmt USING dept_id, dept_name, location; ②
----into子句的execute immediate
sql_stmt := ‘SELECT * FROM emp WHERE empno = :id‘;
EXECUTE IMMEDIATE sql_stmt INTO emp_rec USING emp_id; ③
----returning into子句的execute immediate
sql_stmt := ‘UPDATE emp SET sal = 2000 WHERE empno = :1
RETURNING sal INTO :2‘;
EXECUTE IMMEDIATE sql_stmt USING emp_id RETURNING INTO salary; ④
EXECUTE IMMEDIATE ‘DELETE FROM dept WHERE deptno = :num‘
USING dept_id; ⑤
END;
代码解析:
① 动态执行一个完整的 SQL 语句。
② SQL 语句中存在 3 个参数分别标识为:[:1、:2、:3],因此需要用 USING 关键字对三
个参数分别赋值。
③ 对动态查询语句可以使用 INTO 子句把查询的结果保存到一个变量中,要求该结果
只能是单行。
④ 在 Oracle 的 insert,update,delete 语句都可以使用 RETURNING 子句把操作影响的
行中的数据返回,对 SQL 语句中存在 RETURNING 子句时,在动态执行时可以使用
RETURNING INTO 来接收。
⑥ 动态执行参数中可以是:[:数字]也可以是[:字符串]。
⑥
七、数据库导入导出
1. Oracle 导入导出
Oracle 的备份是 Oracle 操作中常见的工作,常见的备份方案有:逻辑备份(IMP&EXP
命令进行备份)、物理文件备份(脱机及联机备份)、利用 RMAN(Recovery Manager)的增量
物理文件系统备份。ORACLE 数据库的逻辑备份分为四种模式:表空间备份(tablespace)、表
备份(table)、用户备份(user)和完全备份(full)。Oracle 的逻辑备份是使用 IMP&EXP 命令进行
数据导入导出的操作。使用 EXP 命令导出或者使用 IMP 命令导入时,需要 Create Session 系
统权限,但是如果要导出其他的表,必须拥有权限:EXP_FULL_DATABASE。
调用导入导出命令时,首先要估计所需的空间。EXP 命令导出的文件是二进制文件
(*.dmp)只能由对应的 IMP 命令进行读取恢复。导入导出的用途是:
? 备份与恢复
? Oracle 平台更换:可以在相同版本之间进行备份与恢复,Oracle 较低版本的 export
数据文件可以 import 到高版本的 Oracle 数据库中,但是 Oracle 的版本只能是相邻
的,不能垮版本。
2. EXP 导出数据
EXP 命令可以在交互环境下导出数据库中的数据,也可以在非交互环境下执行命令。交
互环境下的命令执行,是一步一步执行的过程。
代码演示:exp 的交互环境
D:\>exp scott/[email protected]_orcl ①
Export: Release 10.2.0.3.0 - Production on 星期一 10月 19 17:04:14 2009
Copyright (c) 1982, 2005, Oracle. All rights reserved.
连接到: Oracle Database 10g Enterprise Edition Release 10.2.0.3.0 - Production
With the Partitioning, OLAP and Data Mining options
输入数组提取缓冲区大小: 4096 > ②
导出文件: EXPDAT.DMP > scott.dmp ③
(2)U(用户), 或 (3)T(表): (2)U > 2 ④
导出权限 (yes/no): yes > yes ⑤
导出表数据 (yes/no): yes > yes ⑥
压缩区 (yes/no): yes > no ⑦
已导出 ZHS16GBK 字符集和 AL16UTF16 NCHAR 字符集
. 正在导出 pre-schema 过程对象和操作
. 正在导出用户 SCOTT 的外部函数库名
. 导出 PUBLIC 类型同义词
. 正在导出专用类型同义词
. 正在导出用户 SCOTT 的对象类型定义
即将导出 SCOTT 的对象...
. 正在导出数据库链接
. 正在导出序号
. 正在导出簇定义
. 即将导出 SCOTT 的表通过常规路径...
. . 正在导出表 BONUS导出了 0 行
. . 正在导出表 DEPT导出了 10 行
. . 正在导出表 EMP导出了 14 行
. . 正在导出表 SALGRADE导出了 5 行
. . 正在导出表 TBLSTUDENT导出了 3 行
. 正在导出同义词
. 正在导出视图
. 正在导出存储过程
. 正在导出运算符
. 正在导出引用完整性约束条件
. 正在导出触发器
. 正在导出索引类型
. 正在导出位图, 功能性索引和可扩展索引
. 正在导出后期表活动
. 正在导出实体化视图
. 正在导出快照日志
. 正在导出作业队列
. 正在导出刷新组和子组
. 正在导出维
. 正在导出 post-schema 过程对象和操作
. 正在导出统计信息
成功终止导出, 没有出现警告。
D:\>
代码解析:
① Exp 是导出命令,该命令后面紧跟“用户名/密码@服务器网络连接”。
② Exp 程序导出时使用的缓冲区大小,缓冲区越大,导出速度越快。直接回车代表使
用默认值 4096B。
③ Exp 命令会把所有要到处的数据导出到一个 Dmp 文件中,该步骤是 Exp 询问导出的
数据文件名称。
④ Exp 程序询问导出整个用户还是导出某个表。默认导出整个用户。
⑤ Exp 程序询问是否导出每张表的访问权限。默认导出访问权限。
⑥ Exp 程序询问是否导出表中的数据。默认导出数据库表中的数据。
⑦ Oracle 表中的数据可能来自不同的分区中的数据块,默认导出时会把所有的数据压
缩在一个数据块上,IMP 导入时,如果不存在连续一个大数据块,则会导入失败
也可以使用 Exp 命令时,设置各种参数,使准备就绪的 Exp 命令不需要与用户交互,按
照参数的要求,Exp 命令会一次性执行导出工作。要指定参数,您可以使用关键字:
EXP KEYWORD=value 或 KEYWORD=(value1,value2,...,valueN)
例如: EXP SCOTT/TIGER GRANTS=Y TABLES=(EMP,DEPT,MGR)
代码演示:exp 的非交互环境
D:\>exp scott/[email protected] file=employee.dmp tables=(emp,dept)
Export: Release 10.2.0.3.0 - Production on 星期一 10月 19 17:38:25 2009
Copyright (c) 1982, 2005, Oracle. All rights reserved.
连接到: Oracle Database 10g Enterprise Edition Release 10.2.0.3.0 - Production
With the Partitioning, OLAP and Data Mining options
已导出 ZHS16GBK 字符集和 AL16UTF16 NCHAR 字符集
即将导出指定的表通过常规路径...
. . 正在导出表 EMP导出了 14 行
. . 正在导出表 DEPT导出了 10 行
成功终止导出, 没有出现警告。
D:\>
3. IMP 导入
IMP 程序导入就是把 Exp 导出的文件重新导入到数据库的过程。导入时也有一些重要的
参数:
? Fromuser:指出导出时 dmp 文件中记载的用户信息。
? Touser:dmp 文件要导入到什么目标用户中。
? Commit:默认是 N,在缓冲区满时是否需要 commit,如果设为 N,需要较大的回滚段。
? Igore: Oracle在恢复数据的过程中,当恢复某个表时,该表已经存在,就要根据ignore
参数的设置来决定如何操作。若 ignore=y,Oracle 不执行 CREATE TABLE 语句,直接
将数据插入到表中,如果插入的记录违背了约束条件,比如主键约束,则出错的记
录不会插入,但合法的记录会添加到表中。若 ignore=n,Oracle 不执行 CREATE TABLE
语句,同时也不会将数据插入到表中,而是忽略该表的错误,继续恢复下一个表。
代码演示:Imp 导入
D:\>imp test/[email protected] file=employee.dmp commit=y full=y
Import: Release 10.2.0.3.0 - Production on 星期一 10月 19 17:54:51 2009
Copyright (c) 1982, 2005, Oracle. All rights reserved.
连接到: Oracle Database 10g Enterprise Edition Release 10.2.0.3.0 - Production
With the Partitioning, OLAP and Data Mining options
经由常规路径由 EXPORT:V10.02.01 创建的导出文件
警告: 这些对象由 SCOTT 导出, 而不是当前用户
已经完成 ZHS16GBK 字符集和 AL16UTF16 NCHAR 字符集中的导入
. 正在将 SCOTT 的对象导入到 EMPLOYEE
. . 正在导入表 "EMP"导入了 14 行
. . 正在导入表 "DEPT"导入了 10 行
即将启用约束条件...
成功终止导入, 没有出现警告。
D:\>
4. 常见问题
? 数据库对象已经存在
一般情况, 导入数据前应该彻底删除目标数据下的表,序列,函数/过程,触发器等。
数据库对象已经存在, 按缺省的 imp 参数,则会导入失败。
如果用了参数 ignore=y,会把 exp 文件内的数据内容导入。
如果表有唯一关键字的约束条件,不合条件将不被导入。
如果表没有唯一关键字的约束条件,将引起记录重复。
? 数据库对象有主外键约束
不符合主外键约束时,数据会导入失败。
解决办法: 先导入主表,再导入依存表。
disable 目标导入对象的主外键约束,导入数据后,再 enable 它们。
? 权限不够
如果要把 A 用户的数据导入 B 用户下, A 用户需要有 imp_full_database 权限。
? 导入大表( 大于 80M ) 时,存储分配失败
默认的 EXP 时,compress = Y,也就是把所有的数据压缩在一个数据块上。
导入时,如果不存在连续一个大数据块,则会导入失败。
导出 80M 以上的大表时,记得 compress= N,则不会引起这种错误。
? Imp 和 Exp 使用的字符集不同
如果字符集不同,导入会失败,可以改变 unix 环境变量或者 NT 注册表里 NLS_LANG 相
关信息。
? Imp 和 Exp 版本不能往上兼容
Imp 可以成功导入低版本 Exp 生成的文件, 不能导入高版本 Exp 生成的文件根据情况我
们可以用。
以上是关于oracle数据库学习笔记的主要内容,如果未能解决你的问题,请参考以下文章