一、数据库分类
通常是按照数据模型的特点将传统数据库系统分成网状数据库、层次数据库和关系数据库三种。
1、网状数据库
顾名思义,网状数据库采用的是以记录类型为结点的网状数据模型,是一种导航式(Navigation)的数据库——用户在操作数据库时不但要指明要访问的对象(数据),还要规定其存取路径。
网状数据库模型对于层次和非层次结构的信息都能比较自然的模拟,在关系数据库出现之前网状DBMS要比层次DBMS用得普遍。在数据库发展史上,网状数据库占有重要地位。
2、层次型数据库
紧随网络型数据库之后出现,它采用层次数据模型(类似于数据结构中的“树”)来模拟现实世界中按层次组织起来的事物。层次数据库管理系统也是按记录来存取数据的,层次数据模型中最基本的数据关系是基本层次关系,它代表两个记录型之间一对多的关系,也叫做双亲-子女关系(Parent-Child Relationship,PCR)。数据库中有且仅有一个记录型无双亲,称为根节点。其他记录型有且仅有一个双亲。
层次数据模型的优点是结构简单、层次清晰、易于理解,并能够提供良好的完整性支持。其缺点包括:处理非层次性联系如多对多联系的数据时比较繁琐,只能通过引入冗余结点或虚拟结点来实现;查询子结点必须通过父结点,即从根节点开始访问,这样降低了数据访问效率;层次型数据库对数据插入和删除有较多限制。
3、关系型数据库(Relationship Database, RDB)
采用二维表结构储存与管理数据,并规定了表内和表间数据的依存关系。可以简单地理解为,关系数据库中的表结构与我们日常生活中经常使用的数据表(比如Office办公软件Word/Excel中的表格)对应,当然关系型数据库中经过抽象后的数据表结构可以支持更多的数据类型,并附加所需的约束条件,这也符合技术来源于现实世界、并服务于现实世界生产活动的本质规律。
关系型数据库采用结构化查询语言(Structured Query Language,SQL)作为客户端程序与数据库服务器间沟通的桥梁——客户端发送SQL指令到服务器端,服务器端执行相关的指令并返回其查询的结果结果。关系模型结构简单、概念单一、易学易用。关系模型的查询效率往往不如非关系模型,需进行优化以提高性能,这一定程度上要增加用户的负担,并对用户在数据库的整体知识上有较高的要求。
二、SQL语句分类
按其功能的不同,Oracle支持的SQL指令可分为数据操作语言语句、数据定义语言语句、事务控制语句、会话控制语句等几种类型。
1、DML
数据操作语言语句(Data manipulation language,DML)用于进行数据的检索和更新操作。
(1)SELECT
其中各子句的执行顺序及主要特性:
1. FROM子句
必须,指定查询目标表。
2. WHERE子句
可选,限定查询条件/预先过滤不符合条件的记录,缺省则不做过滤。
3. GROUP BY子句
可选,显式建立分组,缺省不分组/将表中全部数据做为一组处理。4. HAVING子句
可选,对分组查询结果进行过滤,缺省则不做过滤。
5. SELECT子句
必须,执行查询操作/提取符合条件记录的部分内容。6. ORDER BY子句
可选,查询结果排序,缺省按记录物理存储/添加顺序排列。
Oracle模糊查询中涉及到的通配符有两个:%(百分号)——表示零或多个任意字符的通配符;_(下划线)——标识单个字符的通配符,可以匹配单个任意字符。
WHERE子句用于指定查询条件(过滤掉不符合条件的记录行,最先执行),GROUP BY子句用于指定基于那个字段进行分组,ORDER BY子句用于对分组查询后的结果进行排序(最后执行)。
需要特别注意的是:使用分组函数时,出现在SELECT列表中的字段,如果不是包含在组函数中,那么该字段必须同时在GROUP BY子句中出现。反之,包含在ROUP BY子句中的字段则不必须出现在SELECT列表中。也可换一句话说,如果没有GROUP BY子句,SELECT列表中不允许出现字段(单行函数)与分组函数混用的情况。
此外,需要注意的是,在WHERE子句中不允许使用分组函数。因为,WHERE子句最先被执行,此时尚未进行分组。HAVING中可以使用分组函数。
顺便说明一下,和WHERE子句中不允许使用分组函数类似,由于处理顺序的原因,在WHERE、GROUP BY 和HAVING子句中也不允许使用SELECT字段/表达式列表中的别名。
(2)INSERT
a.插入单行数据
b.表间数据拷贝
其中,subQuery 用于指定为插入操作提供数据的子查询,其返回结果的字段数目、类型及顺序必须与目标表(或指定的赋值字段列表)完全匹配。
c.多表插入
其中,subQuery
用于指定为插入操作提供数据的子查询,其返回结果的字段数目、类型及顺序必须与目标表(table1,table2...)完全匹配。当子查询结果中的某一行满足某个检查条件(condition1,condition2...)时,则将该行记录插入到相应的目标表(table1,table2...)中;最后剩余的记录(不符合任何一个分支的插入条件)被插入到table_else表中,ELSE
INTO子句是可选的(类似于高级编程语言中switch分支结构的default分支)。
可选参数ALL用于指定总是将子查询结果集中全部记录进行条件插入操作——即使某一行记录已满足前面的条件并且已经被插入到相应的数据表,该行记录在后续分支的判断和插入操作中仍将会被再次使用,即它还有可能被插入到其它分支对应的数据表中;参数FIRST则不同——如果某一行记录已满足前面的条件并且已经被插入到相应的数据表,该行记录在后续插入操作中仍将不会被再次使用。如缺省此设置,则默认采用ALL方式。
(3)UPDATE
a.使用表达式更新数据
b.使用子查询更新数据
(4)DELETE
(5)MERGE
MERGE操作用于实现数据合并——根据条件在表中执行数据的修改或插入操作,如果要插入的记录在目标表中已经存在,则执行更新操作、否则执行插入操作。其语法格式如下:
其中,dest_table用于指定要将数据合并到的目标表,source_table(view,sub_query)为提供数据的源表(视图或子查询),ON子句用于指定合并操作中数据的连接条件。针对源表中的每一条记录,如果在目标表中找到与其相应的记录(符合连接条件的记录),则执行WHEN MATCHED THEN分支的UPDATE语句,修改目标表中相应记录;否则执行WHEN NOT MATCHED THEN分支的INSERT语句,将源表的当前记录插入到目标表中。
2、DDL
数据定义语言语句(Data definition language,DDL)用于定义数据的格式和形态,比如定义数据表、视图和索引等数据库对象。
数据库对象是数据库中信息存储、组织和管理的基本单位,具体包括表、约束、视图、索引、序列、存储过程、触发器、数据库用户等多种,常用Oracle数据库对象如图:
(1)建表
新建表的字段名列表可以缺省,此时会缺省使用子查询中结果中的字段名或别名。子查询中查询字段列表中如果出现了表达式,则应指定其表达式别名,否则就只能显
式指定新建表的字段名了(因为不能缺省使用表达式做为新建表的字段名。
创建临时表:用于保存临时性数据,根据其保存数据的时效性可分为事务级临时表和会话级临时表。临时表不存在DML操作时锁定数据的问题。
其中,使用"ON COMMIT DELETE ROWS"选项创建的事务级临时表,使用"ON COMMIT PRESERVE ROWS"选项创建的是会话级临时表。
(2)修改表结构
a.添加字段
b.修改现有字段属性
c.删除字段
d.禁用字段:
在ALTER TABLE语句中使用SET UNUSED子句可以将表中字段设为无用,即将该字段隐藏起来/禁止使用,其主要目的是在业务高峰期直接删除字段(DROP COLUMN)的操作可能有风险,先暂时通过SET UNUSED隐藏该字段,等将来系统空闲时再真正删除它。
(3)删除表
(4)清除表中的数据(截断表)
TRUNCATE与前述DELETE操作的区别在于:DELETE为DML操作,可以回滚,而TRUNCATE为DDL操作,一经执行不可撤销,故其效率要高一些;DELETE操作可以选择删除表中全部或部分数据,而TRUNCATE操作只能删除表中全部数据;如果不再用到表中数据、但又需要保留表的结构,则可该使用TRUNCATE TABLE操作;如果连表的结构也需要了,则可使用DROP TABLE操作将表彻底删除。
(5)重命名表
数据字典
Oracle数据库中的表可分为用户定义的表和数据字典表两类:用户定义的表由用户自己创建并维护,其中保存了用户所需的信息;数据字典表则是由Oracle数据库自动创建并维护的一组表,其中保存的是数据库相关自身信息。本节中我们对数据字典相关知识做简单介绍:
数据字典是Oracle数据库的核心,用于描述数据库及其所有对象。数据字典由一系列只读的表和视图组成,这些表和视图属SYS用户拥有,由Oracle
server负责维护,其内容包括:
- 数据库的物理和逻辑结构
- 对象的定义和空间分配
- 完整性约束条件
- 用户
-
角色
- 权限
-
审计记录
数据字典的内容是动态自动更新的,用户可以通过select语句进行访问。数据字典表/视图主要可分为三类:
- dba -
所有方案包含的对象信息(查看者需拥有DBA权限)
- all – 当前用户可以访问的所有对象信息(包括有权访问的其它方案中的对象)
- user
– 当前用户方案的对象信息
例如:
3、DCL
数据控制语言(Data Control Language,DCL)用于对用户授权或撤销其权限,也可使用角色实现对用户的批量授权或撤销权限,在应用开发层面较少用到。
4、事务控制语句
事务控制语句(Transaction Control Statement)用于实现数据库事务管理。
(1)提交事务
所谓提交事务,就是结束当前事务的运行并确认其所做的数据修改(使之永久生效、不可撤销)。使用COMMIT指令可以实现事务的提交。
数据库编程接口支持手动提交和自动提交两种工作模式。
a.手动提交
手动提交模式下,当遇到COMMIT、DDL或DCL语句时、或者正常退出客户端程序(如SqlPlus)时,正常断开数据库连接),会提交当前事务(提交当前所有已做的修改)。
b.自动提交
自动提交模式下,将每一条语句(即使是DML语句)都作为单独的事务对待——执行一句、自动提交一句,相当于在每一个DML语句之后都附加了一条COMMIT语句。自动提交模式会影响应用程序的性能和事务逻辑,如果应用程序需要事务的完整性,则不能使用自动提交。
Sql Plus中执行SQL语句时缺省设置为非自动提交,也可以使用如下指令显式设置是否自动提交:
上述设置只在本次数据库连接会话有效,待重启Sql Plus后会恢复到其缺省设置。也可以执行下述命令查看其当前提交方式:
如返回结果“autocommit OFF”则为非自动提交,如返回“autocommit IMMEDIATE”则为自动提交。
提交/回滚前数据状态
- 当前事务中数据状态的改变是可以恢复的;
- 当前事务中的DML操作结果只对当前用户(会话)可见,其它用户(会话)看不到当前事务中数据状态的改变,直到当前事务结束;
- 当前事务中DML语句所涉及到的记录行被锁定(记录级锁),在此期间其他用户(会话)只能读取但不能对其进行修改操作;
- 当前事务中DML语句所涉及到的数据表被锁定(表级锁),在此期间其他用户(会话)不允许修改表的结构(添加或删除字段)。事务提交后数据状态
- 事务中对数据的修改永久生效、不可再撤消;
- 数据修改之前的状态永久性丢失、无法恢复;
- 所有的用户(会话)都将看到操作后的结果;
- 记录锁/表级锁被释放,其它用户(会话)可对这些记录进行修改操作、或者修改表的结构;
- 事务中的保存点(Savepoints)被清除;
(2)回滚事务
回滚事务是指结束撤销当前事务所做的数据修改,使数据恢复到事务开始之前的状态,并释放相关的记录锁和表级锁,回滚范围内的保存点(见下文)同时被清除。使用ROLLBACK指令可以实现事务的回滚。
(3)保存点
如果需要,还可以在事务中使用保存点(Savepoint)在当前的事务中的关键点处创建标记,将来就可以回退到指定的标记(保存点)处,以实现事务的部分回滚。保存点可以有多个。例如:SAVEPOINT
p1; ROLLBACK TO p1;
(4)概念性知识
a.什么是事务?什么是锁?
事务就是被绑定在一起作为一个逻辑工作单元的SQL语句分组,如果任何一个语句操作失败那么整个操作就被失败,以后操作就会回滚到操作前状态,或者是上有个节点。为了确保要么执行,要么不执行,就可以使用事务。要将有组语句作为事务考虑,就需要通过ACID测试,即原子性,一致性,隔离性和持久性。
锁:在所以的DBMS中,锁是实现事务的关键,锁可以保证事务的完整性和并发性。与现实生活中锁一样,它可以使某些数据的拥有者,在某段时间内不能使用某些数据或数据结构。当然锁还分级别的。
b.事务的隔离级别有哪些?(简称ACID)
原子性(Atomicity),即不可分割性,事务要么全部被执行,要么就全部不被执行;
一致性(Consistency)或可串性,事务的执行使得数据库从一种正确状态转换成另一种正确状态;
隔离性(Isolation) ,在事务正确提交之前,不允许把该事务对数据的任何改变提供给任何其他事务;
持久性(Durability),事务正确提交后,其结果将永久保存在数据库中,即使在事务提交后有了其他故障,事务的处理结果也会得到保存
c.运行中的事务在下述情况下将结束运行:
- 遇到执行COMMIT语句提交事务
- 遇到ROLLBACK语句回滚
- 遇到DDL或DCL语句
-
用户断开与数据库的连接(会话结束)
- 数据库系统崩溃时
5、会话控制语句
会话控制语句(Session Control Statement)用于动态修改当前用户会话的属性,在应用开发层面极少用到。
三、Oracle中的函数
Oracle函数可分为单行函数和多行函数两大类。
1、单行函数
单行函数是指那些每行输入记录都能得到一行处理结果(输出一行结果)的函数,例如查询员工信息表,根据其中工资字段计算每个雇员的应纳税额,有多少行记录就应得到多少行处理结果。
按其所提供的功能划分,单行函数又可分为字符函数、数值函数、日期函数、转换函数和通用函数五类。
(1)字符函数
(2)数值函数
(3)日期函数
(4)转换函数
(5)通用函数
a.nvl(exp1, exp2)用于将空值转换为指定的具体值——先计算参数/表达式exp1的值,如果其值NULL,则返回exp2的值,否则返回exp1的值。
b.decode函数用于实现多路分支结构,其语法格式:
其逻辑是,首先计算第一个表达式(col|expression)的值;再依次与各搜索字表达式(search1, search2,...)相比较,如果匹配则返回相应的结果(result1, result2,..);如果均不匹配,返回表达式default的值;如果未指定default表达式,则返回空值。
c.case表达式也用于实现多路分支结构,和decode函数的功能类似,其语法格式如下:
例如:
2、分组函数(也称多行函数)
多行函数则是多行输入记录经处理后只输出一行结果,例如统计员工信息表中全部员工的平均工资、或工资总额,多行记录(多个员工)只能得到一个统计结果。
(1)NULL值得处理
除COUNT(*)以外的所有分组函数均忽略空值。
avg(comm)效果等价于sum(comm)/count(comm),而不是sum(comm)/count(*)。
如果分组函数的参数为表达式(不是单一的字段),则忽略表达式结果中的空值,例如:
SELECT sum(sal), sum(comm),
sum(sal+comm), sum(sal)+sum(comm) FROM emp;
其中sum(sal+comm)统计的是工资与补助均不为空值的员工的总收入(如果sal、comm中有一个为空值NULL,则该行忽略不计)
与单行函数的嵌套层次无限制有所不同,分组函数嵌套使用时最多可以嵌套两层,这是因为内层分组函数的查询结果(多个数值)再经外层分组函数处理后只能得到一个单一的值,无法也没必要再进一步进行分组处理。