SQL Server
一. 子查询
在SQL语言中,一个SELECT…FROM…WHERE语句称为一个查询块,将一个查询块嵌套在另一个查询块的WHERE子句中的查询称为子查询。子查询分为嵌套子查询和相关子查询两种。
嵌套子查询的求解方法是由里向外处理,即每个子查询在其上一级查询处理之前求解,子查询的结果作为其父查询的查询条件。子查询只执行一次,且可以单独执行;
嵌套子查询使得可以用一系列简单查询构成复杂的查询,从而明显增强了SQL的查询处理能力。
a) 带有比较运算符的嵌套子查询(要求子查询返回的值为一行一列)
b) In的嵌套子查询(子查询返回的值为多行一列)
c) EXISTS的嵌套子查询:如果子查询的结果非空,即记录条数1条以上,则EXISTS (子查询)将返回真(true),否则返回假(false)。
d) 相关子查询:子查询依靠外部查询获得值。这意味着子查询是重复执行的,为外部查询可能选择的每一行均执行一次。子查询不能单独执行。
二. 视图
1. 视图的概念
视图是另一种查看数据库中一个或多个表中的数据的方法。视图基于实际的数据表(基表)或别的视图而创建。视图是一种虚拟表,也就是说,视图中并不存储实际的数据。任何对视图的操作,都会转换为到基表的操作。
2. 视图的用途:
筛选表中的行
防止未经许可的用户访问敏感数据
将多个物理数据表抽象为一个逻辑数据表
3. 创建视图
语法:
CREATE VIEW view_name
AS
<SELECT语句>
4. 对视图的编辑:
因为视图中的数据来源基表,因此对视图进行增删改操作时,其命令中只能包含一个基表的数据。因此通过视图来修改数据有许多的限制,所以在实际开发中一般视图仅作查询使用。
三. 索引
1. 索引的概念
索引是通过创建索引页的方式将表中指定列的数据进行存放,并提供指针以指向数据表中的数据,然后根据指定的排列次序排列这些指针。数据库使用索引的方式与使用书的目录很相似:通过搜索索引找到特定的值,然后跟随指针到达值的行。
2. 索引的优点
通过创建唯一性索引,可以保证数据库表中每一行数据的唯一性;
可以大大加快数据的检索速度,这也是创建索引的最主要的原因;
可以加速表和表之间的连接,特别是在实现数据的参考完整性方面特别有意义;
通过使用索引,可以在查询的过程中,使用优化隐藏器,提高系统的性能。
3. 索引的缺点
创建索引和维护索引要耗费时间,这种时间随着数据量的增加而增加;
索引需要占物理空间,除了数据表占数据空间之外,每一个索引还要占一定的物理空间,如果要建立聚簇索引,那么需要的空间就会更大;
当对表中的数据进行增加、删除和修改的时候,索引也要动态的维护,这样就降低了数据的维护速度。
4. 适合建立索引的列
在经常需要搜索的列上,可以加快搜索的速度;
在作为主键的列上,强制该列的唯一性和组织表中数据的排列结构;
在经常用在连接的列上,这些列主要是一些外键,可以加快连接的速度;
在经常需要根据范围进行搜索的列上创建索引,因为索引已经排序,其指定的范围是连续的;
在经常需要排序的列上创建索引,因为索引已经排序,这样查询可以利用索引的排序,加快排序查询时间;
5. 不适合建立索引的列
表中只会包含不多的数据。为小型表创建索引反而可能影响效率。通过索引进行查询所花的时间比在表中逐行搜索更多。
对于那些只有很少数据值的列也不应该增加索引。这是因为,由于这些列的取值很少,例如人事表的性别列,在查询的结果中,结果集的数据行占了表中数据行的很大比例,即需要在表中搜索的数据行的比例很大。增加索引,并不能明显加快检索速度;
对于那些定义为text, image和bit数据类型的列不应该增加索引。这是因为,这些列的数据量要么相当大,要么取值很少;
当修改性能远远大于检索性能时,不应该创建索引。这是因为,修改性能和检索性能是互相矛盾的。当增加索引时,会提高检索性能,但是会降低修改性能。当减少索引时,会提高修改性能,降低检索性能。因此,当修改性能远远大于检索性能时,不应该创建索引。
6. 索引的类型
根据索引的顺序与数据表的物理顺序是否相同,可以把索引分成两种类型
聚集索引:数据表的物理顺序与索引顺序一致(物理排序);
因为表中的数据将按照索引页中的数据排序方式来进行排序,因此,只能为一个表创建一个聚集索引。默认情况会为主键列创建唯一聚集索引
非聚集索引:数据表的物理顺序与索引顺序不一致(逻辑排序)
索引页上的数据将进行排序,但是和数据表中的数据排列顺序不一致。因此可以为一个表最多创建249个非聚集索引
7. 创建索引
语法:
CREATE [UNIQUE] [CLUSTERED|NONCLUSTERED] INDEX index_name
ON table_name(column_name[,column_name]...)
[WITH FILLFACTOR = x]
UNIQUE:是否是唯一索引
CLUSTERED:聚集索引
NONCLUSTERED:非聚集索引
WITH FILLFACTOR:1-100之间的值,表示索引页的填充因子
示例:
CREATE NONCLUSTERED INDEX ix_Storage_quantity
ON Storage(quantity) WITH FILLFACTOR = 30
四. 事务
1. 事务的概念
事务是一种机制、一个操作序列,它包含了一组数据库操作命令,并且所有的命令作为一个整体一起向系统提交或者撤消操作请求,即这一组数据库命令要么都执行,要么都不执行,因此事务是一个不可分割的工作逻辑单元,在数据库系统上执行并发操作时事务是作为最小的控制单元来使用的。它特别适用于多用户同时操作的数据库系统。例如,航空公司的订票系统、银行、保险公司以及证券交易系统等。
2. 事务的种类:
自动提交事务(默认模式):将每条单独的T-SQL语句视为一个事务。
显式事务:由用户管理的事务
T-SQL使用下列语句来管理事务:
开始事务:BEGIN TRANSACTION
提交事务:COMMIT TRANSACTION
回滚事务:ROLLBACK TRANSACTION
3. 使用显式事务:
--创建变量来对错误编号进行累计
declare @error int
set @error = 0
--开启事务
begin tran
--执行相应的SQL操作
--每执行一个操作,都需要对错误编号进行累加
set @error = @error + @@error
--执行操作
set @error = @error + @@error
--所有命令执行完后,
--如果累加的错误编号等于,表示所有的命令都执行成功,提交事务
--否则回滚事务
if (@error = 0)
commit tran
else
rollback tran
五. 存储过程
1. 存储过程概述
存储过程是一组T-SQL语句,存成一定名称,作为一个工作单元执行。存储过程可以从另一存储过程中调用,从客户机应用程序中调用或者从T-SQL命令中调用,进行预定的操作。
存储过程有如下的优点:
允许模块化的程序设计:
存储过程一旦创建完成并存储于数据库中,即可在我们的程序中反复调用。另外,通过将业务逻辑和策略编写在存储过程中,不仅可以让不同的应用程序共享,也可以要求所有的客户端去使用相同的存储过程来达到数据访问与更新的一致性。
更快的执行速度:
当执行批处理和T-SQL程序代码时,SQL Server必须先检查语法是否正确,接着加以编译、优化,然后再执行它,因此如果我们要执行的T-SQL代码非常庞大,那么执行前的处理操作是会耗掉一些时间的。对于存储过程而言,当它们被创建时就已经检索过语法的正确性、编译,并加以优化,因此当执行存储过程时,可以立即直接执行,自然速度会比较快;
存储过程在它第一次被执行后会保留在内存中,因此以后的调用并不需要再将存储过程从磁盘中加载。
有效降低网络流量:
假设某一项操作需要数百行的T-SQL代码来完成,如果我们是从客户端将这些代码传送到后端的SQL Server来执行,则在网络上传输的将是程序程序代码的数千或数万个字符;而如果我们事先将这些代码编写成一个存储过程,则只需从客户端调用该存储过程的名称即可执行它,它时在网络上传输的仅仅是存储过程名称的几个字符。
较好的安全机制:
如果我们不希望某一位用户有权限直接去访问某个数据表,但是又必须要求他针对该表执行特定的操作。如果想达到此目的,我们可以将该用户所能针对表执行的操作编写成一个存储过程,并赋予他执行该存储过程的权限,如此一来,虽然该用户没有权限直接访问表,但仍然可以通过执行存储过程来完成所需的操作。
2. 存储过程类型
系统存储过程
SP_
扩展存储过程
XP_
用户自定义存储过程
3. 创建和调用存储过程
创建|修改存储过程的基本语法:
CREATE|ALTER PROC[EDURE] procedure_name
[<@parameter_name data_type>[=default][output][,...n]]
AS
sql_statement
创建|修改存储过程的最复杂部分是生成内容(sql_statement部分),所有的智能都在这里
简单存储过程
--创建简单存储过程
CREATE PROCEDURE myProc1
AS
SELECT * FROM Students
--执行上述存储过程:
EXECUTE myProc1
带输入参数的存储过程
--创建带输入参数的存储过程
CREATE PROCEDURE myProc2
@Sid char(2)
AS
SELECT * FROM Students WHERE Sid=@Sid
--执行上述存储过程:
EXECUTE myProc2 '01'
带输入输出参数的存储过程
--创建带输入和输出参数的存储过程
CREATE PROCEDURE myProc3
@Uid char(2),@Pwd varchar(20),@Result char(4) output
AS
IF EXISTS(SELECT * FROM UserInfo WHERE Uid=@Uid AND Pwd=@Pwd)
SET @Result='合法'
ELSE
SET @Result='非法'
--执行上述存储过程
DECLARE @Result char(4)
EXECUTE myProc3 '01','abc',@Result output
SELECT @Result
带返回值的存储过程
--创建有返回值的存储过程
CREATE PROCEDURE myProc4
@Uid char(2),@Pwd varchar(20)
AS
IF EXISTS(SELECT * FROM UserInfo WHERE Uid=@Uid AND Pwd=@Pwd)
RETURN 0
ELSE
RETURN 1
--执行上述存储过程
DECLARE @Result int
EXECUTE @Result=myProc4 '01','abc'
SELECT @Result
六. 自定义函数
自定义函数类似存储过程,将一组SQL命令封装起来,区别在于自定义函数只能通过返回值的方式来返回结果。因此可以将自定义函数放置在任何SQL命令中。例如通过自定义函数进行复杂计算,然后将内容最为查询条件提供给查询语句。
语法:
CREATE|ALERT FUNCTION funName(@parament_name data_type,...n) returns data_type
AS
BEGIN
SQL命令
RETURN 值
END
创建一个函数的示例:
create FUNCTION GetName(@mID int) returns NVARCHAR(20)
AS
BEGIN
DECLARE @name(16);
select @name = name from tableName where id = @id
RETURN @name
END
七. 游标
SQL中查询语句查询的结果是一个数据集,为了能够对数据集中的数据进行逐行计算,可以使用游标。不过要注意的是,游标的效率不高,所有只有在必要的时候才使用游标。
declare @fname varchar(20),@lname varchar(20)
--根据一个查询语句创建一个游标对象
declare myCursor cursor for
select fname,lname from employee
--打开游标
open myCursor
--通过游标逐行读取数据,并将读取的数据赋值给变量
fetch next from myCursor into @fname,@lname
--判断游标状态,是否存在下一行,如果有的话通过循环的方式读取每一条记录
while @@fetch_status = 0
begin
print @fname + '.' + @lname
fetch next from myCursor into @fname,@lname
end
--关闭游标
close myCursor
--释放游标对象
deallocate myCursor
已有 0 人发表留言,猛击->> 这里<<-参与讨论
ITeye推荐