1.定义视图的好处是可以直接对用户赋予视图的权限,通过视图查数据,这样就可以不用对用户赋予表的权限,实现表的安全。并且一张表可以建立多个不同的视图,也就是对于不同的操作员可以在一张表上定义对个不同的视图,简化了逻辑。但是视图的缺点是:除了执行用户定义的SQL语句外还要执行视图的语句,并且视图大部份是不能执行更新操作(除了基表是单表并且不能有聚集函数,distinct等修饰的情况),因此视图主要用于查询。
对于在定义视图的过程中我们不能在语句中进行排序,如果要对得到的结果排序,我们可以对视图进行查询操作,然后排序,例如:select * from 视图名 order by name
如果要对视图进行排序我们必须用top关键字,或者FOR XML例如
create view 视图名 as select top 50 * from table order by name
2.对于SQL2008的表值参数的传递,大大简化了批量插入和批量更新(经典的操作)。
3.交叉表处理方面了数据库结构的设计。
4.几个常用的系统存储过程(sp_helptext 查看数据对象的代码,sp_help 查看数据对象的结构, sp_depends 查看数据对象的依赖关系, sp_rename 重命名数据对象)
set nocount on不应该放在增删改的存储过程中,如果设置了客户端将得不到返回受影响的行数,对于查询我们只要表所有可以设置。存储过程中的返回值是返回给调用存储过程的函数或存储过程的,客户端代码(比如C#)不会接收这个返回值。
5.几个系统状态标识符:@@fetch_status 0表示语句成功 -1表示语句失败或者不在结果集中 -2表示提取的行不存在
@@rowcount 表示上个操作影响的行数
实例:
declare @m int, @n int --使用局部变量保存游标记录
declare mycur cursor
for select * from table1
open mycur
fetch from mycur into @m,@n
while @@fetch_status=0
begin
set @m+=1;
set @n+=1;
fetch next from mycur into @m ,@n
end
close mycur;
deallocate mycur
6.使用游标变量
delcare @mycurbian cursor
declare mucur cursor
for select * from table1
set @mycurbian=mucur
open @mycurbian --可以开始使用游标变量进行操作了
7.触发器分after和instead of两种,其中after触发器只能应用于表,并且在操作之后执行(insert,delete,update),而instea of既能适用于表也能适用于视图,但是它是适用于操作之前,并且代替操作。 如果在表上创建约束和触发器,那么约束将在inste of之后发生,并且在after触发器之前。值得注意的是,在触发器中我们会经常用到inserted和deleted表,从中回去一些值来判断一些逻辑,然后在作出处理。对于在触发器中要对inserted和deleted表进行大量的重复访问建议先建一个临时表,然后在临时表上建立索引,以后的操作都在临时表上处理,因为在inserted和deleted表中没有索引,每次访问表都是全表扫描。例如:
select * into #biao from inserted; --把inserted表的内容插入临时表#biao中
create unique clustered index idx_name on #biao(keycol) --创建临时表索引
8.触发器中判断某列是否更改:update(column)返回bool值,colunms_update()返回数字。触发器的禁止和启用
disable trigger mytri on tablename --禁止在tablename表上使用mytri
enable trigger mytri on tablename --启用在tablename表上使用mytri
disable trigger all on tablename --禁止在tablename表上使用所有触发器
enable trigger all on tablename --启用在tablename表上的所有的触发器
9.受索引影响最大的是select,其次是update和delete,而对于insert是否创建索引没有关系。索引的创建是程序员,但是使用索引却是查询优化器。索引分聚集和非聚集,分唯一和非唯一,也能分组合和非组合。
10.创建索引:对于数据量大,更新操作少,特别是对于查询操作多的,最好建在重复值最少的列上,对于where子句中精确匹配的列。
不宜对更新操作多的列创建索引,尽量少创建组合索引,对于只有很少能确定范围值的列上不宜创建索引。比如0和1为值的列。
创建唯一索引后我们就不能对该列输入相同的值,我们在定义主键的时候系统会自动为我们创建一个唯一索引。
11.复制一张表的结构和数据
select * into table1 from table2
这样会把表2的结构和数据复制到表1中去
12.对于2张数据表的“交集”“差集”“并集”的出来 interset,except,union
对于SQL2008提供了更强大的操作merge(详细查资料)
13.简单case
CASE input_expression
WHEN when_expression THEN result_expression
[ ...n ]
[
ELSE else_result_expression
END
搜索case
CASE
WHEN Boolean_expression THEN result_expression
[ ...n ]
[
ELSE else_result_expression
END
创建局部临时表,全局临时表和表变量
CREATE TABLE #t(x INT PRIMARY KEY) --局部临时表
CREATE TABLE ##t(x INT PRIMARY KEY) --全局临时表
delcare @biao table(x int,y nvarchar(60)) --表变量
表变量是存储在内存中,而临时表放在磁盘上,如果要读取速度就用表变量,如果内存紧张就用临时表
14.对于有循环的我们可以用break中断或continue继续,对于一般的程序我们可以用goto语句,最后介绍一个不常用语句waitfor语句:
waitfor time '17:30';
select name from table1 --将在17:30执行
waitfor delay '01:20';
select * from table2 --延迟1小时20分钟
15.对于表结构的修改
alter table table1 add 年龄 int --添加列
alter table table1 drop column 年龄 --删除列
alter table table1 drop constraint 约束名 --删除表约束
alter table table1 alter column 年龄 nvachar(100) --修改字段的类型
16.一些特殊的操作
set iddentity_insert 表名 on --设置这个后就能对自增长的列进行插入
newid()将返回全球唯一的内容,也可以用它来随即排序
truncate table table1 --删除表中所有数据
17.返回当前插入,删除,更新的数据
我们平时对增删改的操作只能看到一个受影响的行数,但是不能返回那些数据发生了变化,不能像查询那样返回一个数据集合,现在有了output关键字后我们能得到我们想要的呈现效果。格式如下
delete from table1 output deleted.* where id=100 --对于删除
update table1 set age=25 output deleted.age,inserted.age from table1 --更新
insert table1 output inserted.age values(10,'张华','男') --对于插入
18.函数一般分2种:系统函数和用户自定义函数,其中用户自定义函数分:标量函数,内联表值函数和多语句表函数
现在着重说说自定义函数
标量函数只是返回一个标量值和C#的函数差不多
CREATE FUNCTION fnCOM_2Digits (@sValue VARCHAR(2)) --创建函数名和参数
RETURNS VARCHAR(2) --定义返回类型
AS
BEGIN
IF (LEN(@sValue) < 2)
SET @sValue = '0' + @sValue
RETURN @sValue
END
内联函数返回一个表
CREATE FUNCTION fnGetEmployeesByCity (@sCity VARCHAR(30)) --创建函数名和参数
RETURNS TABLE --定义返回表类型
AS
RETURN
(
SELECT FirstName, LastName, Address
FROM Employees
WHERE City = @sCity
)
GO
多语句表值函数
CREATE FUNCTION Sales.ufnSalesByCustomerMS (@CustomerID int)
RETURNS @table TABLE
( ProductID int PRIMARY KEY NOT NULL,
ProductName nvarchar(50) NOT NULL,
TotalSales numeric(38,6) NOT NULL,
TotalInventory int NOT NULL )
AS
BEGIN
INSERT INTO @table
SELECT P.ProductID, P.Name, SUM(SD.LineTotal) AS Total, 0
FROM Production.Product AS P
JOIN Sales.SalesOrderDetail SD ON SD.ProductID = P.ProductID
JOIN Sales.SalesOrderHeader SH ON SH.SalesOrderID = SD.SalesOrderID
WHERE SH.CustomerID = @CustomerID
GROUP BY P.ProductID, P.Name;
UPDATE @table
SET TotalInventory = dbo.ufnGetTotalInventoryStock(ProductID);
RETURN;
END;
19.事务
@@TRANCOUNT 表示当前还有多少个事务,如果其中一个事务用了回滚,则所有事务都会回滚,但当一个事务提交,其实并没有提交,只是修改了@@TRANCOUNT 的值,所以在嵌套事务中并不存在真正的嵌套,当begin tran相当于把@@TRANCOUNT 加1,当commit tran 相当于@@TRANCOUNT 减1,当rollback则@@TRANCOUNT 减少到0;但我们可以用save tran 事务节点名字 的方法让某个事务回滚到指定的事务节点。
在对事物进行错误处理的时候我们大多数用的是try catch的方式(2005以后,2000采用的是@@error),在catch中其实程序是有提交事务的功能,只有对错误级别大于一定级别才不能提交(错误级别好像是在10以后,在10以前是警告),我们可以手动的设置对所有的出现的错误都回滚事务,方法:在事务前加上 set xact_sbort on 。
我们在编写程序的时候可以查找事务中的错误出现在哪行用error_number();处理事务状态xatc_state()函数 ,如果xatc_state()返回1表示有事务并且可以 提交,返回0表示没有事务,返回-1表示有事务,但是不能提交。
20.动态SQL
在我们用exec执行动态SQL的时候,由于exec的动态SQL不提供输入和输出参数,所以对于在执行完一个动态批处理后返回的数据处理起来就比较麻烦,我们解决的办法是在执行动态SQL之前创建一个临时表,然后把批处理的结果插入到临时表中,然后在向临时表中提取数据。
例子:insert into #table exec(sql); ---把执行完的动态批处理SQL插入到临时表中
select * from #table ---获取数据
其实我们也可以先定义临时表,然后把临时表名一起放在动态SQL中,让批处理的结果插入也放在动态SQL中
creat table #table(id int)
declare @sql nvarchar(200)
set @sql="insert into #table (id) select count(*) from biao1;"; ---把临时表直接加入到动态SQL中
exec(@sql) --执行动态SQL
exec at实现对远程数据库服务器执行动态SQL并且还能带参数
sp_addlinkedserver创建一个链接的服务器,使其允许对分布式的。例子:
Exec sp_droplinkedsrvlogin DBVIP,Null
Exec sp_dropserver DBVIP
EXEC sp_addlinkedserver
@server='DBVIP',--被访问的服务器别名
@srvproduct='',
@provider='SQLOLEDB',
@datasrc="/Server2" --要访问的服务器
EXEC sp_addlinkedsrvlogin
'DBVIP', --被访问的服务器别名
'false',
NULL,
'sa', --帐号
'thankyoubobby' --密码
Select * from DBVIP.pubs.dbo.orders
创建优于exec的动态SQL:sp_executesql ,它主要比exec多了1个外部接口(提供输入输出参数)execute sp_executesql
N'select * from pubs.dbo.employee where job_lvl = @level', --相当于存储过程的函数体
N'@level tinyint', --相当于存储过程的参数声明
@level = 35 --相当于存储过程的执行