本文是刚接触oracle时候的记录,主要是sql
SQL相关
概念
索引
视图 view
-
定义:
在 SQL 中,视图是基于 SQL 语句的结果集的可视化的表。
视图包含行和列,就像一个真实的表。视图中的字段就是来自一个或多个数据库中的真实的表中的字段。我们可以向视图添加 SQL 函数、WHERE 以及 JOIN 语句,我们也可以提交数据,就像这些来自于某个单一的表。
数据库的设计和结构不会受到视图中的函数、where 或 join 语句的影响。
-
语法:
CREATE VIEW view_name AS
SELECT column_name(s)
FROM table_name
WHERE condition
-
实例:
CREATE VIEW [Category Sales For 1997] AS
SELECT DISTINCT CategoryName,Sum(ProductSales) AS CategorySales
FROM [Product Sales for 1997]
GROUP BY CategoryName
-
更新:
CREATE OR REPLACE VIEW view_name AS
SELECT column_name(s)
FROM table_name
WHERE condition
-
删除:
DROP VIEW view_name
触发器
存储过程
-
简介
- 将【常用的或复杂】的工作,预先使用SQL语句写好,并用一个指定的名称存储起来,那么以后在需要使用时,直接调用execute即可。 【理解:SQL函数】
-
特点
-
种类
- 系统存储过程:以sp_开头,用来进行系统的各项设定.取得信息.相关管理工作
如sp_help就是取得指定对象的相关信息
- 扩展存储过程:以xp_开头,用来调用操作系统提高的功能
如 exec master..xp_cmdshell 'ping 192.169.0.22'
- 用户自定义的存储过程【函数】
-
基本语法
create procedure sp_name
事务
-
简介
事务处理可以用来维护数据库的完整性,它保证成批的SQL操作要么完全执行,要么完全不执行。关系数据库设计把数据存储放在多个表中,使数据容易操纵、维护和重用,设计良好的数据库模式都是关联的。
若没有发生错误语句,则写数据库,若发生错误,则进行回退(撤销)以恢复数据库到某个已知且安全的状态。
-
术语
事务【transaction】:指一组SQL语句
回退【rollback】:指撤销指定SQL语句的过程
提交【commit】:指将未存储的SQL语句写入数据库表
保留点【savepoint】:指事务处理中设置的临时占位符,可以对它发布回退,与整个事务回退不同。
ps:事务处理用来管理DML中的INSERT、UPDATE、DELETE语句,不能回退SELECT及DDL
-
使用
-
创建
不同数据库语法不通,例如SQL Server
BEGIN TRANSACTION
……
COMMIT TRANSACTION
MySQL中
START TRANSACTION
……
-
回退ROLLBACK
DELETE FROM Orders;
ROLLBACK;
-
使用COMMIT
一般的SQL语句都是直接针对数据库表执行和编写。这就是所谓的隐含提交,即提交(写和保存)操作都是自动进行的。
但是,在事务处理块中,提交不会隐含进行。
在SQL Server例子
BEGIN TRANSACATION
DELETE OrderItems WHERE order_num = 12345
DELETE Orders WHERE order_num = 12345
COMMIT TRANSACTION
在Oracle中
DELETE OrderItems WHERE order_num = 12345
DELETE Orders WHERE order_num = 12345
COMMIT
-
使用保存点
简单的ROLLBACK和COMMIT就可以写入或撤销整个事务,对于复杂的事务处理可能需要要部分提交或者回退。
为了支持部分回退事务,必须能在事务块中合适的位置放置占位符,这样如果需要回退,则可以回退到某个占位符。
MySQL与Oracle中
SAVEPOINT delete1;
ROLLBACK TO delete1;
RELESE SAVEPOINT delete1; // 删除存储点
SQL Server中
SAVE TRANSACTION delete1;
ROLLBACK TRANSACTION delete1;
ps:可以在SQL代码中设置任意多的保留点,保留点越多,可以按自己的意愿灵活回退。
-
其他
a、在循环中提交事务,影响性能
b、使用自动提交性能。一定要使用手动控制事务的提交。
-
总结
事务最大的好处在于保护的操作的原子性
SQL用回退的方式来控制语句的进行,有些像汇编语言中控制循环的样子
游标
-
游标就是select的结果集,可以从结果集中进行fetch数据。
-
创建
DECLARE CURSOR custCursor
IS
SELECT * FROM customers
WHERE cust_email IS NULL
-
使用游标
DECLARE TYPE custCursor IS REF CURSOR
RETURN customers%ROWTYPE;
DECLARE custRecord customers%ROWTYPE
OPEN CURSOR custCursor;
FETCH custCursor INTO custRecord;
CLOSE custCursor;
BEGIN
OPEN custCursor;
LOOP
FETCH custCursor INTO custRecord;
EXIT WHEN custCursor%NOTFOUND;
...
END LOOP;
CLOSE custCursor;
END
DML、DDL与DCL
DML:Data Manipulation Language数据操作语言
DDL:Data Definition Language 数据定义语言
DCL:Data Control Language 数据库控制功能:用来设置或者更改数据库用户或角色权限的语句,包括(grant,deny,revoke等)在默认状态下,只用sysadmin,dbcreator,db_owner和db_securityadmin等人员才有权利执行DCL.
SQL基础
SELECT:聚合函数与GROUP BY
五个聚合函数
ps: 所有聚合函数可以操作一个变量,这个变量可以是列或者表达式;聚合函数的结果是一个常量,它显示在结果中不同的列上
分组汇总
- 语法:
GROUP BY 分组表达式
HAVING 分组条件
ps:分组表达式:一般为字段名,对指定字段名进行分组,
分组条件:对分组汇总后数据进入结果集的筛选条件,一般为集合函数或者常量。
PS:
SQL为每个定义的组产生一个列值,每个组只返回一行,不返回详细信息。
在包含GROUP BY子句的查询语句中,SELECT 子句后的所有字段列表,除集合函数为,都应该包含在GROUP BY 子句中,否则将出差。
不要在含有空值的列上是由GROUP BY子句,因为空值会当作一个组来处理。
2、带有HAVING 的GROUP BY 子句
HAVING 子句定义应用到分组行中的条件,对分组行的意义与WEHRE对每行的意义相同。
查询平均成绩大于80学生的学号和平均成绩:
SELECT student_id, AVG(grade) AS 平均成绩
FROM student_course
GROUP BY student_id
HAVING AVG(grade)>80
查询不及格的人数大于2的课程号与人数
SELECT course_id, count(*)
FROM student_course
WHERE grade<60
GROUP BY course_id
HAVING count(*)>2
- WHERE / GROUP BY / HAVING
WHERE子句从数据源中去掉不符合其搜索条件的数据【每行】
GROUP BY 子句搜集结果集中的数据行到各个组中,统计函数为各个组计算统计值
HAVING 子句 去掉不符合其组搜索条件的各组数据行
计算字段
简介
由于表中的字段与需要的字段格式上或者内容上存在不一张,可以通过计算字段【field】来完成对于两个字段的格式与数值上的处理。
拼接字段
用“+”或者“||”来连接两个字段
SELECT name || '(' || country || ')' AS title
FROM vendors
ORDER BY name;
执行算术计算
SELECT ID,
price,
number,
prict*number AS totle
FROM OrderItems
WHERE ID = 20111;
表连接 JOIN
Left join即:以左表为中心,将右表通过key连接到左表。保留左表中所有记录,若右表中存在多条记录,则插入多条记录(左表部分重复)
Right join即:以右表为中心,将左表通过key连接到右表。保留右表中所有记录,若左表中存在多条记录,则插入多条记录(右表部分重复)
Inner join即:去调左右表中key值没有对应的部分,若存在多个对应,则插入多条记录。
对于date类型的查询如下
where e.Begintime >= to_date('2014-09-10 00:00:00','yyyy-mm-dd hh24:mi:ss')
对于字符串的处理’%名字%’:
if(searchText!="")
{
sql.append(" and (c.organization like \'%");
sql.append(searchText.local8Bit().data());
sql.append("%\')");
}
Join的模型是左连接与右连接的模型,
Select 列表 from tableA () tableB。
两个表成左右分布,左连接将以左表为主,右表中没有的项也同样查出,多个匹配,则出现多次。相当于将右表插入到左表中,若没有匹配则丢失。
右连接与左连接相同
结果集连接 UNION
-
功能:UNION运算符可以将多个结果集求并集,形成一个结果集。
-
要求:源表的列类型、名称及个数必须一致
-
实例:
SELECT k.id AS id, k.mingzi AS name, '开关' AS type
FROM kaiguan k WHERE id<10
UNION
SELECT d.id AS id, d.mingzi AS name, '刀闸' AS type
FROM daozha d WHERE id<10;
-
其他连接符
INTERSECT:可以将形成的两个结果集求交集.要求同UNION
EXCEPT:(除……之外)从左表中查询去除右表结果中存在的行
子查询【嵌套查询】
- 指嵌入在其他SQL语句的SELECT语句,也称嵌套查询。
使用上根据select返回结果的不同使用不同的处理
单行子查询
多行子查询
-
多行子查询指返回单列多行数据的子查询,使用多行比较符(IN, ALL, ANY)
-
IN:
实例:
SELECT *
FROM produucts
WHERE supplierID in (
SELEC supplierid
FROM suppliers
WHERE city = 'London'
)
-
ANY | SOME:
操作符必须与单行操作符结合,匹配于子查询的任意一结果即可。
【any的英文用法】:等价与查询单价大于类别号为3的产品中最低价格的产品。
SELECT productid, productName
FROM products
WHERE unitPrice > ANY (
SELECT unitPrict
FROM products
WHERE CateGoryID = 3
)
-
ALL:
操作符必须与单行操作符结合,匹配于子查询的所有结果。
【all的英文用法】:等价于大于类别编号为3的产品中最高价格的产品信息。
SELECT productid, productName
FROM products
WHERE unitPrice > ALL (
SELECT unitPrict
FROM products
WHERE CateGoryID = 3
)
-
EXISTS:
用于子查询只需要返回一个真值或假值,而不需要返回具体的数据时。当子查询的结果集返回一行或多行时,返回为True,否则返回为False
实例:[查询产品表products中供应商的城市为'London'的产品编号与供应商编号]
SELECT productid, supplierid
FROM products P
WHERE EXISTS(
SELECT * FROM suppliers S
WHERE S.supplierid = P.supplierid AND city = 'London'
)
PS:EXISTS 关键字引入的查询语句中SELECT 常有*
在FROM 子句中使用子查询
INSET\UPDATE\DELETE语句中使用子查询
条件查询
(1)
Select top 100 State,JoinState, (
case when State=1 and Joinstate=0 then 2
when State=1 and JoinState=1 then 1
else 0 end)
as usestate
from UserInfo
(2)
select ID,namer=(case when(score<='50') then '实习'
when(score>'2000' and score<='3000' ) then '医师'
when(score>'3000' and score<='5000' ) then '主治医师'
when(score>'5000' and score<='10000' ) then '副主任医师'
when(score>'10000' and score<='20000' ) then '主任医师'
else '健康大使' end ),
(SELECT count(id) FROM Question WHERE UserID = dbo.jk01_Member.ID) as questionnum
from jk01_Member
限制结果集行数
-
Oracle中为每个结果集增加了一个表示行号的列,这个列名为rownum
工资从高到低排序的前6名
SELECT *
FROM employee
WHERE rownum<=6
ORDER BY FSalary DESC
-
分页查询
在进行数据检索时,当结果数据非常多,若要同时显示在一个界面中,不仅查看起来非常麻烦,而且也会占用过多的系统资源,常用的解决方案就是分页查询。
分页查询的核心技术就是“限制结果集行数”。假设每页显示的行数为pagesize,当前页数为currindex,那么只要查询从第currindex * pagesize 开始的pagesize 条数据就是当前页中的数据。
更新数据 UPDATE
语法:
update 表名称 set 列名称 = 新值 where 列名称 = 某值
实例:
UPDATE Person SET Address = 'Zhongshan 23', City = 'Nanjing'
WHERE LastName = 'Wilson'
插入数据 INSERT
语法:
INSERT INTO 表名称 VALUES (值1, 值2,....)
INSERT INTO table_name (列1, 列2,...) VALUES (值1, 值2,....)
实例:
INSERT INTO Persons (LastName, Address) VALUES ('Wilson', 'Champs-Elysees')
删除数据 DELETE/TRUNCATE
语法:
DELETE FROM 表名称 WHERE 列名称 = 值
实例:
DELETE FROM Person WHERE LastName = 'Wilson'
TRUNCATE 与 DELETE
TRUNCATE为一页一页清楚,日志只记录页删除记录,所以不会效率高,但不触动触发器。不可 回滚。
提交COMMIT
- 尽量多用 commit 语句提交事务,可以及时释放资源、解锁、释放日志空间、减少管理花费;
- 在频繁的、性能要求比较高的数据操作中,尽量避免远程访问,如数据库链等,访问频繁的表可以常驻内存: alter table ... cache ;
新建表 create table
CREATE TABLE 表名称
(
列名称1 数据类型,
列名称2 数据类型,
列名称3 数据类型,
....
)
实例:
CREATE TABLE Persons
(
Id_P int,
LastName varchar(255),
FirstName varchar(255),
Address varchar(255),
City varchar(255)
)
注意:对于4字节整形number(10), 对于2字节整形number(5),对于1字节number(3)
增删改列 alter table 表名 add/drop/alter
1、增加列
ALTER TABLE table_name
ADD column_name datatype
2、删除列 -- 有些数据库不支持
ALTER TABLE table_name
DROP COLUMN column_name
3、修改列的数据类型
ALTER TABLE table_name
ALTER COLUMN column_name datatype
修改表名 rename to
rename 旧表名 to 新表名
insert into 表名1 字段名 select 字段名 from 表名2
rename district to olddistrict;
create table district
(
列名 数据类型,
……
)
insert into district (ID,MINGZI,GISRDFID) select ID,MINGZI,GISRDFID from olddistrict
约束条件 constraint
-
非空:NOT NLL
-
唯一:UNIQUE
-
主外键:primary key/foreign key
-
限制范围:check
-
实例:
CREATE TABLE Persons
(
Id_P int NOT NULL CHECK (Id_P>0),
LastName varchar(255) NOT NULL,
FirstName varchar(255),
Address varchar(255),
City varchar(255)
)
CREATE TABLE Persons
(
Id_P int NOT NULL,
LastName varchar(255) NOT NULL,
FirstName varchar(255),
Address varchar(255),
City varchar(255),
CONSTRAINT chk_Person CHECK (Id_P>0 AND City='Sandnes')
)
建索引 create index
- 在不读取整个表的情况下,索引使数据库应用程序可以更快地查找数据。
语法:
CREATE INDEX index_name
ON table_name (column_name)
实例:
CREATE INDEX PersonIndex
ON Person (LastName DESC)
SQL优化
设计表
-
合适的索引,创建表的时候,应尽量建立主键。选择合适的列建立索引,索引对于SELECT多而INSERT/UPDATE少的表很适合。数据重复量大的列不要建立二叉树索引,可以采用位图索引;组合索引的列顺序尽量与查询条件列顺序保持一致;对于数据操作频繁的表,索引需要定期重建,以减少失效的索引和碎片。
-
建表时字段不允许为空
原因:在查询数据的时候往往需要在WHERE条件中多加一个判断条件“IS NOT NULL”,这样的条件对于查询的性能产生了很大的影响,有可能就因为多个条件查询导致查询变的非常的慢;另外允许为空的数据可能你会导致查询结果出现不准确的问题。
格式:
增加整形列:ALTER TABLE TABLE_NAME ADD COLUMN_NAME INT NOT NULL DEFAULT(0);
增加字符列:ALTER TABLE TABLE_NAME ADD COLUMN_NAME NVARCHAR(50) NOT NULL DEFAULT(”)
-
建立自增列时,单独再给自增列添加唯一约束
原因:所以如果要保证ID是唯一的,单单只设置自增值不行,需要给字段设置主键或者唯一约束
PS: Oracle是序列
SELECT
-
查询时一定要制定字段查询,少用号
原因:
l 查询时一定不能使用””来代替字段来进行查询,无论你查询的字段有多少个,就算字段太多无法走索引也避免了解析”*”带来的额外消耗。
2 查询字段值列出想要的字段,避免出现多余的字段,字段越多查询开销越大而且可能会因为多列出了某个字段而引起查询不走索引。
-
尽量少嵌套子查询,这种查询会消耗大量的 CPU 资源;
-
对于有比较多or 运算的查询,建议分成多个查询,用 union all 联结起来;
-
多表查询的查询语句中,选择最有效率的表名顺序。 Oracle 解析器对表解析从右到左,所以记录少的表放在右边。
索引列使用
-
避免在索引列上使用会函数或表达式
WHERE 子句中,如果索引列是函数的一部分.优化器将不使用索引而使用全表扫描。
低效:
SELECT …
FROM DEPT
WHERE SAL * 12 > 25000;
高效:
SELECT …
FROM DEPT
WHERE SAL > 25000/12;
-
避免在索引列上使用NOT,通过使用 >= 、 <= 等,避免使用 NOT 命令
通常,我们要避免在索引列上使用 NOT, NOT 会产生在和在索引列上使用函数相同的影响当ORACLE遇到NOT, 他就会停止使用索引转而执行全表扫描.
-
对于有联接的列,即使最后的联接值为一个静态值,优化器是不会使用索引的。
select * from employss
where first_name||''||last_name ='Beill Cliton';
系统优化器对基于 last_name 创建的索引没有使用。当采用下面这种 SQL 语句的编写, Oracle 系统就可以采用基于 last_name 创建的索引。
select * from employee
where first_name ='Beill' and last_name ='Cliton';
-
避免使用前置通配符
WHERE 子句中,如果索引列所对应的值的第一个字符由通配符 (WILDCARD) 开始,索引将不被采用。
SELECT USER_NO,USER_NAME,ADDRESS
FROM USER_FILES
WHERE USER_NO LIKE '%109204421';
这种情况下Oracle使用全表扫描。
-
避免出现索引列自动转换
当比较不同数据类型的数据时 , ORACLE 自动对列进行简单的类型转换。
假设 EMP_TYPE 是一个字符类型的索引列
SELECT USER_NO,USER_NAME,ADDRESS
FROM USER_FILES
WHERE USER_NO = 109204421
这个语句被 ORACLE 转换为:
SELECT USER_NO,USER_NAME,ADDRESS
FROM USER_FILES
WHERE TO_NUMBER(USER_NO) = 109204421
因为内部发生的类型转换 , 这个索引将不会被用到
减少排序
- 带有 DISTINCT,ORDER BY,GROUP BY,UNION,MINUS,INTERSECT 的 SQL 语句会启动 SQL 引擎执行耗费资源的排序(SORT)功能,DISTINCT 需要一次排序操作, 而其他的至少需要执行两次.
实例:
一个 UNION 查询,其中每个查询都带有GROUP BY子句, GROUP BY会触发嵌入排序(NESTED SORT); 这样,每个查询需要执行一次排序;然后在执行 UNION 时,又一个唯一排序 (SORT UNIQUE) 操作被执行而且它只能在前面的嵌入排序结束后才能开始执行。嵌入的排序的深度会大大影响查询的效率通常,带有UNION、MINUS、INTERSECT的SQL语句都可以用其他方式重写.
PS:貌似与前一个OR用union all的方式有些矛盾。
当 SQL 语句需要 UNION 两个查询结果集合时,这两个结果集合会以UNION ALL 的方式被合并,然后在输出最终结果前进行排序
ORDER BY/GROUP BY
-
ORDER BY 语句决定了 Oracle 如何将返回的查询结果排序。 Order by 语句对要排序的列没有什么特别的限制,也可以将函数加入列中(象联接或者附加等)。 但任何在 Order by 语句的非索引项或者有计算表达式都将降低查询速度。【是否可认为Order by会使用索引,但要】
-
由于 GROUP BY 实际上也同样会进行排序操作,而且与 ORDER BY 相比,GROUP BY 主要只是多了排序之后的分组操作。当然,如果在分组的时候还使用了其他的一些聚合函数,那么还需要一些聚合函数的计算。所以,在GROUP BY 的实现过程中,与 ORDER BY 一样也可以利用到索引。
WHERE子句中连接顺序
-
ORACLE 采用自下而上的顺序解析 WHERE 子句,根据这个原理, 当在 WHERE 子句中有多个表联接时, WHERE 子句中排在最后的表应当是返回行数可能最少的表,有过滤条件的子句应放在 WHERE
-
实例:
设从 emp 表查到的数据比较少或该表的过滤条件比较确定,能大大缩小查询范围,则将最具有选择性部分放在 WHERE 子句中的最后:
select * from emp e,dept d
where d.deptno >10 and e.deptno =30 ;
如果 dept 表返回的记录数较多的话,上面的查询语句会比下面的查询语句响应快得多。
select * from emp e,dept d
where e.deptno =30 and d.deptno >10;
-
最好不要在 WHERE 子句中使用函或表达式,如果要使用的话,最好统一使用相同的表达式或函数,这样便于以后使用合理的索引
学习前言
-- oracle编程艺术现主要学习了前11章,后续准备学习14章,其余各章近期不打算学习。
-- 发现学习过程中主要分三大部分,
第一部分Oracle体系结构:2,3,4,5。主要讲解Oracle的基础,包括硬盘(文件)、内存、进程。对于编码的影响主要是进程的设计。
第二部分Oracle精髓:6,7,8,9。主要讲解锁、并发、事务、redo/undo;对于编码的影响在于数据完整性与高并发的思考,以及redo与undo思考。
第三部分orcle存储:10,11。主要讲解表与索引。索引的建立更多是的方便读取,损失少部分写的基础上,大大加快读的效率。聚簇、位图索引等各个新感念。对于编码的影响也在于如何加快读的效率,以及数据的存储方式。
第一部分:Orcle体系结构
数据文件
主要介绍数据库中的各种文件,其中最重要的是数据文件以及重做日志文件,次要为参数文件与控制文件,其余了解
参数文件
oracle中有很多参数文件,用于一般启动数据库时的初始化设置
参数文件的演化:init.ora[pfile] --> spfile<ORACLE_SID>
相互转化的命令:reate spfile from pfile / create pfile="路径" from spfile
重要的命令与视图:v$parameter 及 show parameter命令
控制文件
参数文件告诉oracle控制文件的位置,控制文件告诉oracle重做日志文件的位置
对于开发人员不重要,对于DBA很重要
重做日志文件
用途:用于恢复实例崩溃,恢复介质崩溃,恢复误操作
在线重做日志:日志文件组;日志切换;检查点;DBWn;受平均恢复时间与高峰大量用户修改的博弈影响
归档重做日志:oracle两种运行方式,在放生介质问题时的处理差异
数据文件
存储结构:表空间 --> 段 --> 区段
逻辑结构:表空间 --> 表(可以位于多个段上)
警告文件
oracle的inf
密码文件
允许远程sysdba或者管理员访问数据库
闪回日志
加快慢的时间点数据库恢复的效率,目的在于加快误操作的恢复
临时文件
用来存储大规模的排序操作、散列操作的中间结果,在内存不足时
第二部分:Oracle精髓
第8章
exec dbms_stats.gather_table_stats( user, 'T', cascade=>true );
收集user用户'T'表的索引信息
创建undo空间及修改系统的undo空间
create undo tablespace undo_small
datafile '/home/ora11gr2/app/ora11gr2/oradata/orcl/undo_small.dbf'
size 10m reuse
autoextend off
/
alter system set undo_tablespace = undo_small;
V$UNDOSTAT
动态性能视图,对于监视所生成的undo数量非常有用,还可以用来运行时间最长的查询持续时间。
oracle的输出
dbms_output.putline(sql%rowcount || ' rows updated ');
自动提交
-- 流行的ORACLE编程API(ODBC,JDBC)都会在update后,默认的自动提交(我觉得应该是可配置的),这样会造成事务的原子性操作破坏。
分布式事务
数据库链接
-- 一个数据库对象,描述从你的实例登录到另一个实例
-- SELECT * FROM T@another_database
站点、协调器
-- 协调器就是登录机器,协调不同站点数据库进行操作
限制
-- 不能在数据链接上发出commit
-- 不能在数据链接上完成DDL
-- 不能在数据连接上发出SAVEPOINT