(精华)2020年8月14日 数据库设计 SqlServer详解篇

一:sqlserver 字段类型详解

bit 整型
bit数据类型是整型,其值只能是0、1或空值。这种数据类型用于存储只有两种可能值的数据,如Yes 或No、True 或False 、On 或Off.
注意:很省空间的一种数据类型,如果能够满足需求应该尽量多用。

tinyint 整型
tinyint 数据类型能存储从0到255 之间的整数。它在你只打算存储有限数目的数值时很有用。这种数据类型在数据库中占用1 个字节.
注意:如果bit类型太单调不能满足您的需求,您可以考虑用tinyint类型,因为这个类型相对也是比较安全的,不接受恶意脚本内容的嵌入。

smallint 整型
smallint 数据类型可以存储从- 2的15次幂(-32768)到2的15次幂(32767)之间的整数。这种数据类型对存储一些常限定在特定范围内的数值型数据非常有用。这种数据类型在数据库里占用2 字节空间.
注意:如果tinyint类型太单调不能满足您的需求,您可以考虑用smallint类型,因为这个类型相对也是比较安全的,不接受恶意脚本内容的嵌入。

int 整型
int 数据类型可以存储从- 2的31次幂(-2147483648)到2的31次幂 (2147483 647)之间的整数。存储到数据库的几乎所有数值型的数据都可以用这种数据类型。这种数据类型在数据库里占用4个字节.
注意:如果smallint也不能够满足您的需求,您可以考虑用长度更大的int类型。

decimal 精确数值型
decimal 数据类型能用来存储从-10的38次幂-1到10的38次幂-1的固定精度和范围的数值型数据。使用这种数据类型时,必须指定范围和精度。 范围是小数点左右所能存储的数字的总位数。精度是小数点右边存储的数字的位数
numeric 精确数值型
numeric数据类型与decimal 相似。

smallmoney 货币型
smallmoney 数据类型用来表示钱和货币值。这种数据类型能存储从-214748.3648 到214748.3647 之间的数据,精确到货币单位的万分之一
money 货币型
money数据类型用来表示钱和货币值。这种数据类型能存储从-9220亿到9220 亿之间的数据,精确到货币单位的万分之一

float 近似数值型
float 数据类型是一种近似数值类型,供浮点数使用。说浮点数是近似的,是因为在其范围内不是所有的数都能精确表示。浮点数可以是从-1.79E+308到1.79E+308 之间的任意数

real 近似数值型
real 数据类型像浮点数一样,是近似数值类型。它可以表示数值在-3.40E+38到3.40E+38之间的浮点数
Smalldatetime 日期时间型
smalldatetime 数据类型用来表示从1900年1月1日到2079年6月6日间的日期和时间,精确到一分钟

datetime 日期时间型
datetime数据类型用来表示日期和时间。这种数据类型存储从1753年1月1日到9999年12月31日间所有的日期和时间数据, 精确到三百分之一秒或3.33毫秒 .

cursor 特殊数据型
cursor 数据类型是一种特殊的数据类型,它包含一个对游标的引用。这种数据类型用在存储过程中,而且创建表时不能用

timestamp 特殊数据型
timestamp 数据类型是一种特殊的数据类型,用来创建一个数据库范围内的唯一数码。 一个表中只能有一个timestamp列。每次插入或修改一行时,timestamp列的值都会改变。尽管它的名字中有“time”, 但timestamp列不是人们可识别的日期。在一个数据库里,timestamp值是唯一的

Uniqueidentifier 特殊数据型
Uniqueidentifier数据类型用来存储一个全局唯一标识符,即GUID。GUID确实是全局唯一的。这个数几乎没有机会在另一个系统中被重建。可以使用NEWID 函数或转换一个字符串为唯一
标识符来初始化具有唯一标识符的列 .

char 字符型
char数据类型用来存储指定长度的定长非统一编码型的数据。当定义一列为此类型时,你必须指定列长。当你总能知道要存储的数据的长度时,此数据类型很有用。例如,当你按邮政编码加4个字符格式来存储数据时,你知道总要用到10个字符。此数据类型的列宽最大为8000 个字符.

varchar 字符型 varchar数据类型,同char类型一样,用来存储非统一编码型字符数据。与char 型不一样,此数据类型为变长。当定义一列为该数据类型时,你要指定该列的最大长度。 它与char数据类型最大的区别是,存储的长度不是列长,而是数据的长度 .

text 字符型
text 数据类型用来存储大量的非统一编码型字符数据。这种数据类型最多可以有231-1或20亿个字符.

nchar 统一编码字符型
nchar 数据类型用来存储定长统一编码字符型数据。统一编码用双字节结构来存储每个字符,而不是用单字节(普通文本中的情况)。它允许大量的扩展字符。此数据类型能存储4000种字符,使用的字节空间上增加了一倍.

nvarchar 统一编码字符型
nvarchar 数据类型用作变长的统一编码字符型数据。此数据类型能存储4000种字符,使用的字节空间增加了一倍.

ntext 统一编码字符型
ntext 数据类型用来存储大量的统一编码字符型数据。这种数据类型能存储230 -1或将近10亿个字符,且使用的字节空间增加了一倍

binary 二进制数据类型
binary数据类型用来存储可达8000 字节长的定长的二进制数据。当输入表的内容接近相同的长度时,你应该使用这种数据类型.

varbinary 二进制数据类型
varbinary 数据类型用来存储可达8000 字节长的变长的二进制数据。当输入表的内容大小可变时,你应该使用这种数据类型

image 二进制数据类型
image 数据类型用来存储变长的二进制数据,最大可达231-1或大约20亿字节

---------------------------------------------------
(1)二进制数据类型
  二进制数据包括 Binary、Varbinary 和 Image
  Binary 数据类型既可以是固定长度的(Binary),也可以是变长度的。
  Binary[(n)] 是 n 位固定的二进制数据。其中,n 的取值范围是从 1 到 8000。其存储窨的大小是 n + 4 个字节。
  Varbinary[(n)] 是 n 位变长度的二进制数据。其中,n 的取值范围是从 1 到 8000。其存储窨的大小是 n + 4个字节,不是n 个字节。
  在 Image 数据类型中存储的数据是以位字符串存储的,不是由 SQL Server 解释的,必须由应用程序来解释。例如,应用程序可以使用BMP、TIEF、GIF 和 JPEG 格式把数据存储在 Image 数据类型中。

(2)字符数据类型

字符数据的类型包括 Char,Varchar 和 Text
  字符数据是由任何字母、符号和数字任意组合而成的数据。
  Varchar 是变长字符数据,其长度不超过 8KB。Char 是定长字符数据,其长度最多为 8KB。超过 8KB 的ASCII 数据可以使用Text数据类型存储。例如,因为 Html 文档全部都是 ASCII 字符,并且在一般情况下长度超过 8KB,所以这些文档可以 Text 数据类型存储在SQL Server 中。

(3)Unicode 数据类型

Unicode 数据类型包括 Nchar,Nvarchar 和Ntext
  在 Microsoft SQL Server 中,传统的非 Unicode 数据类型允许使用由特定字符集定义的字符。在 SQL Server安装过程中,允许选择一种字符集。使用 Unicode 数据类型,列中可以存储任何由Unicode 标准定义的字符。在 Unicode 标准中,包括了以各种字符集定义的全部字符。使用Unicode数据类型,所战胜的窨是使用非 Unicode 数据类型所占用的窨大小的两倍。
  在 SQL Server 中,Unicode 数据以 Nchar、Nvarchar 和 Ntext 数据类型存储。使用这种字符类型存储的列可以存储多个字符集中的字符。当列的长度变化时,应该使用Nvarchar 字符类型,这时最多可以存储 4000 个字符。当列的长度固定不变时,应该使用 Nchar 字符类型,同样,这时最多可以存储4000 个字符。当使用 Ntext 数据类型时,该列可以存储多于 4000 个字符。

(4)日期和时间数据类型

日期和时间数据类型包括 Datetime 和 Smalldatetime两种类型
  日期和时间数据类型由有效的日期和时间组成。例如,有效的日期和时间数据包括“4/01/98 12:15:00:00:00 PM”和“1:28:29:15:01AM 8/17/98”。前一个数据类型是日期在前,时间在后一个数据类型是霎时间在前,日期在后。在 Microsoft SQL Server中,日期和时间数据类型包括Datetime 和 Smalldatetime 两种类型时,所存储的日期范围是从 1753 年 1 月 1 日开始,到9999 年12 月 31 日结束(每一个值要求 8 个存储字节)。使用 Smalldatetime 数据类型时,所存储的日期范围是 1900年 1 月 1日 开始,到 2079 年 12 月 31 日结束(每一个值要求 4 个存储字节)。
  日期的格式可以设定。设置日期格式的命令如下:
  Set DateFormat {format | @format _var|
  其中,format | @format_var 是日期的顺序。有效的参数包括 MDY、DMY、YMD、YDM、MYD 和 DYM。在默认情况下,日期格式为MDY。
  例如,当执行 Set DateFormat YMD 之后,日期的格式为年 月 日 形式;当执行 Set DateFormat DMY 之后,日期的格式为日 月有年 形式

(5)数字数据类型

数字数据只包含数字。数字数据类型包括正数和负数、小数(浮点数)和整数
  整数由正整数和负整数组成,例如 39、25、0-2 和 33967。在 Micrsoft SQL Server 中,整数存储的数据类型是    Int,Smallint和 Tinyint。Int 数据类型存储数据的范围大于 Smallint 数据类型存储数据的范围,而 Smallint 据类型存储数据的范围大于Tinyint 数据类型存储数据的范围。使用 Int 数据狗昔存储数据的范围是从 -2 147 483 648 到 2 147 483 647(每一个值要求4个字节存储空间)。使用 Smallint 数据类型时,存储数据的范围从 -32 768 到 32 767(每一个值要求2个字节存储空间)。使用Tinyint 数据类型时,存储数据的范围是从0 到255(每一个值要求1个字节存储空间)。
  精确小娄数据在 SQL Server 中的数据类型是 Decimal 和 Numeric。这种数据所占的存储空间根据该数据的位数后的位数来确定。
  在SQL Server 中,近似小数数据的数据类型是 Float 和 Real。例如,三分之一这个分数记作。3333333,当使用近似数据类型时能准确表示。因此,从系统中检索到的数据可能与存储在该列中数据不完全一样。

(6)货币数据表示正的或者负的货币数量 。

在 Microsoft SQL Server 中,货币数据的数据类型是Money 和 Smallmoney
  Money数据类型要求 8 个存储字节,Smallmoney 数据类型要求 4 个存储字节。

(7)特殊数据类型

特殊数据类型包括前面没有提过的数据类型。特殊的数据类型有3种,即    Timestamp、Bit 和 Uniqueidentifier。
  Timestamp 用于表示SQL Server 活动的先后顺序,以二进投影的格式表示。Timestamp 数据与插入数据或者日期和时间没有关系。
  Bit 由 1 或者 0 组成。当表示真或者假、ON 或者 OFF 时,使用 Bit 数据类型。例如,询问是否是每一次访问的客户机请求可以存储在这种数据类型的列中。
  Uniqueidentifier 由 16 字节的十六进制数字组成,表示一个全局唯一的。当表的记录行要求唯一时,GUID是非常有用。例如,在客户标识号列使用这种数据类型可以区别不同的客户。

2.用户定义的数据类型

用户定义的数据类型基于在 Microsoft SQL Server 中提供的数据类型。当几个表中必须存储同一种数据类型时,并且为保证这些列有相同的数据类型、长度和可空性时,可以使用用户定义的数据类型。例如,可定义一种称为   postal_code 的数据类型,它基于 Char 数据类型。
  当创建用户定义的数据类型时,必须提供三个数:数据类型的名称、所基于的系统数据类型和数据类型的可空性。

(1)创建用户定义的数据类型

创建用户定义的数据类型可以使用 Transact-SQL 语句。系统存储过程 sp_addtype 可以来创建用户定义的数据类型。其语法形式如下:
  sp_addtype {type},[,system_data_bype][,‘null_type’]
  其中,type 是用户定义的数据类型的名称。system_data_type 是系统提供的数据类型,例如 Decimal、Int、Char   等等。 null_type 表示该数据类型是如何处理空值的,必须使用单引号引起来,例如’NULL’、‘NOT NULL’或者’NONULL’。
  例子:
  Use cust
  Exec sp_addtype ssn,‘Varchar(11)’,"Not Null’
  创建一个用户定义的数据类型 ssn,其基于的系统数据类型是变长为11 的字符,不允许空。
  例子:
  Use cust
  Exec sp_addtype birthday,datetime,‘Null’
  创建一个用户定义的数据类型 birthday,其基于的系统数据类型是 DateTime,允许空。
  例子:
  Use master
  Exec sp_addtype telephone,'varchar(24),‘Not Null’
  Eexc sp_addtype fax,‘varchar(24)’,‘Null’
  创建两个数据类型,即 telephone 和 fax

(2)删除用户定义的数据类型

当用户定义的数据类型不需要时,可删除。删除用户定义的数据类型的命令是 sp_droptype {‘type’}。
  例子:
  Use master
  Exec sp_droptype ‘ssn’
  注意:当表中的列还正在使用用户定义的数据类型时,或者在其上面还绑定有默认或者规则时,这种用户定义的数据类型不能删除。

SQL SERVER的字段类型说明

以下为SQL SERVER7.0以上版本的字段类型说明。SQL SERVER6.5的字段类型说明请参考SQL SERVER提供的说明。

字段类型 描述
bit 0或1的整型数字
int 从-231(-2,147,483,648)到231(2,147,483,647)的整型数字
smallint 从-215(-32,768)到215(32,767)的整型数字
tinyint 从0到255的整型数字

decimal 从-1038到1038-1的定精度与有效位数的数字
numeric decimal的同义词

money 从-263(-922,337,203,685,477.5808)到263-1(922,337,203,685,477.5807)的货币数据,最小货币单位千分之十
smallmoney 从-214,748.3648到214,748.3647的货币数据,最小货币单位千分之十

float 从-1.79E+308到1.79E+308可变精度的数字
real 从-3.04E+38到3.04E+38可变精度的数字

datetime 从1753年1月1日到9999年12日31的日期和时间数据,最小时间单位为百分之三秒或3.33毫秒
smalldatetime 从1900年1月1日到2079年6月6日的日期和时间数据,最小时间单位为分钟

timestamp 时间戳,一个数据库宽度的唯一数字
uniqueidentifier 全球唯一标识符GUID

char 定长非Unicode的字符型数据,最大长度为8000
varchar 变长非Unicode的字符型数据,最大长度为8000
text 变长非Unicode的字符型数据,最大长度为2^31-1(2G)

nchar 定长Unicode的字符型数据,最大长度为8000
nvarchar 变长Unicode的字符型数据,最大长度为8000
ntext 变长Unicode的字符型数据,最大长度为2^31-1(2G)

binary 定长二进制数据,最大长度为8000
varbinary 变长二进制数据,最大长度为8000
image 变长二进制数据,最大长度为2^31-1(2G)

-------------------------------------
Bit
1位,值为0或1
Int
Integer
4字节,值为-231~231-1
Smallint
2字节,值为-215~215-1
Tinyint
1字节,值为0~255
Decimal (p,s)
数字数据,固定精度为P,宽度为S
Numeric
Money
8字节,存放货币类型,值为-263~263-1
Small money
4字节,存放货币类型,值为-214748.3648~+214748.3647近似数值数据类型
Float (n)
N在1~24之间,4字节,7位精度
N=1~7为real
N在25~53之间,8字节,15位精度
=8~15为float
Datetime
8字节,描述某天的日期和时刻,值的精确度为1/300秒
Smalldatetime
4字节,描述某天的日期和时刻,精度为分钟
Cursor
对游标的引用
Timestamp
8字节,存放在数据库内唯一的数据
Uniqueidentifier
16字节,存放全局唯一标识(GUID)
Char (n)
非unicode字符串的固定长度,n=1~8000
Character (n)
Varchar (n)
可变长度,非unicode字符串n=1~8000
Char varying(n)
Text
服务器代码页中可变长度非unicode数据。最大长度为231-1个字符
Nchar
固定长度unicode字符串n=1~4000
National character (n),
National char(n)
Nvarchar
固定长度unicode字符串n=1~4000
National character varying(n)
Ntext
可变长度unicode数据,最大长度为230-1个字符
National text
Binary (n)
固定长度二进制数据,n在1~8000之间,存储空间为n+4字节
Varbinary (n)
可变长度二进制数据,n=1~8000
Binary varying (n)
Tmage
可变长度二进制数据,大小为0~231-1
注意:
1) 对于数值型数据类型,宽度(scale)是指存储在小数点后的数字位数,而精度(precision)是指能存储的包含小数点在内的所有数字位数。
2) money和small money的存储宽度为4。
3) 时间戳列值在每一行更新时系统自动更新,时间戳列不能是关键字或关键字的一部分。
4) 唯一标识数据类型不能使用算术操作符(如+、-等),这种数据类型只能使用相等比较操作。Unicode是所有字符集的一致存储数据的标准。它要使用两倍于非Unicode数据存储的存储空间。

二:sqlserver 自定义函数的使用

用户自定义函数

查看当前数据库所有函数
–查询所有已创建函数
select definition,* from sys.sql_modules m join sys.objects o on m.object_id = o.object_id
and type in(‘fn’, ‘if’, ‘tf’);

创建函数
if (object_id(‘fun_add’, ‘fn’) is not null)
drop function fun_add
go
create function fun_add(@num1 int, @num2 int)
returns int
with execute as caller
as
begin
declare @result int;
if (@num1 is null)
set @num1 = 0;
if (@num2 is null)
set @num2 = 0;
set @result = @num1 + @num2;
return @result;
end
go
调用函数
select dbo.fun_add(id, age) from student;

–自定义函数,字符串连接
if (object_id(‘fun_append’, ‘fn’) is not null)
drop function fun_append
go
create function fun_append(@args nvarchar(1024), @args2 nvarchar(1024))
returns nvarchar(2048)
as
begin
return @args + @args2;
end
go

select dbo.fun_append(name, ‘abc’) from student;

修改函数
alter function fun_append(@args nvarchar(1024), @args2 nvarchar(1024))
returns nvarchar(1024)
as
begin
declare @result varchar(1024);
–coalesce返回第一个不为null的值
set @args = coalesce(@args, ‘’);
set @args2 = coalesce(@args2, ‘’);;
set @result = @args + @args2;
return @result;
end
go

select dbo.fun_append(name, ‘#abc’) from student;

返回table类型函数
–返回table对象函数
select name, object_id, type from sys.objects where type in (‘fn’, ‘if’, ‘tf’) or type like ‘%f%’;

if (exists (select * from sys.objects where type in (‘fn’, ‘if’, ‘tf’) and name = ‘fun_find_stuRecord’))
drop function fun_find_stuRecord
go
create function fun_find_stuRecord(@id int)
returns table
as
return (select * from student where id = @id);
go

select * from dbo.fun_find_stuRecord(2);

三:sqlserver 自定义函数的使用

游标
游标可以对一个select的结果集进行处理,或是不需要全部处理,就会返回一个对记录集进行处理之后的结果。
1、游标实际上是一种能从多条数据记录的结果集中每次提取一条记录的机制。游标可以完成:
# 允许定位到结果集中的特定行
# 从结果集的当前位置检索一行或多行数据
# 支持对结果集中当前位置的进行修改
由于游标是将记录集进行一条条的操作,所以这样给服务器增加负担,一般在操作复杂的结果集的情况下,才使用游标。SQL Server 2005有三种游标:T-SQL游标、API游标、客户端游标。

 2、游标的基本操作
      游标的基本操作有定义游标、打开游标、循环读取游标、关闭游标、删除游标。
 A、 定义游标

declare cursor_name --游标名称
cursor [local | global] --全局、局部
[forward only | scroll] --游标滚动方式
[read_only | scroll_locks | optimistic] --读取方式
for select_statements --查询语句
[for update | of column_name …] --修改字段

 参数:
 forward only | scroll:前一个参数,游标只能向后移动;后一个参数,游标可以随意移动
 read_only:只读游标
 scroll_locks:游标锁定,游标在读取时,数据库会将该记录锁定,以便游标完成对记录的操作
 optimistic:该参数不会锁定游标;此时,如果记录被读入游标后,对游标进行更新或删除不会超过

 B、 打开游标
      open cursor_name;
      游标打开后,可以使用全局变量@@cursor_rows显示读取记录条数

 C、 检索游标
      fetch cursor_name;
      检索方式如下:
         fetch first; 读取第一行
         fetch next; 读取下一行
         fetch prior; 读取上一行
         fetch last; 读取最后一行
         fetch absolute n; 读取某一行
            如果n为正整数,则读取第n条记录
            如果n为负数,则倒数提取第n条记录
            如果n为,则不读取任何记录
         fetch pelative n
            如果n为正整数,则读取上次读取记录之后第n条记录
            如果n为负数,则读取上次读取记录之前第n条记录
            如果n为,则读取上次读取的记录

 D、 关闭游标
      close cursor_name;

 E、 删除游标
      deallocate cursor_name;

 3、游标操作示例

–创建一个游标
declare cursor_stu cursor scroll for
select id, name, age from student;
–打开游标
open cursor_stu;
–存储读取的值
declare @id int,
@name nvarchar(20),
@age varchar(20);
–读取第一条记录
fetch first from cursor_stu into @id, @name, @age;
–循环读取游标记录
print ‘读取的数据如下:’;
–全局变量
while (@@fetch_status = 0)
begin
print ‘编号:’ + convert(char(5), @id) + ‘, 名称:’ + @name + ‘, 类型:’ + @age;
–继续读取下一条记录
fetch next from cursor_stu into @id, @name, @age;
end
–关闭游标
close area_cursor;

–删除游标
–deallocate area_cursor;

四:sqlserver 异常处理

异常
在程序中,有时候完成一些Transact-SQL会出现错误、异常信息。如果我们想自己处理这些异常信息的话,需要手动捕捉这些信息。那么我们可以利用try catch完成。
TRY…CATCH 构造包括两部分:一个 TRY 块和一个 CATCH 块。如果在 TRY 块中所包含的 Transact-SQL 语句中检测到错误条件,控制将被传递到 CATCH 块(可在此块中处理该错误)。
CATCH 块处理该异常错误后,控制将被传递到 END CATCH 语句后面的第一个 Transact-SQL 语句。如果 END CATCH 语句是存储过程或触发器中的最后一条语句,控制将返回到调用该存储过程或触发器的代码。将不执行 TRY 块中生成错误的语句后面的 Transact-SQL 语句。
如果 TRY 块中没有错误,控制将传递到关联的 END CATCH 语句后紧跟的语句。如果 END CATCH 语句是存储过程或触发器中的最后一条语句,控制将传递到调用该存储过程或触发器的语句。
TRY 块以 BEGIN TRY 语句开头,以 END TRY 语句结尾。在 BEGIN TRY 和 END TRY 语句之间可以指定一个或多个 Transact-SQL 语句。CATCH 块必须紧跟 TRY 块。CATCH 块以 BEGIN CATCH 语句开头,以 END CATCH 语句结尾。在 Transact-SQL 中,每个 TRY 块仅与一个 CATCH 块相关联。
# 错误函数
TRY…CATCH 使用错误函数来捕获错误信息。
ERROR_NUMBER() 返回错误号。
ERROR_MESSAGE() 返回错误消息的完整文本。此文本包括为任何可替换参数(如长度、对象名称或时间)提供的值。
ERROR_SEVERITY() 返回错误严重性。
ERROR_STATE() 返回错误状态号。
ERROR_LINE() 返回导致错误的例程中的行号。
ERROR_PROCEDURE() 返回出现错误的存储过程或触发器的名称。

 示例

–错误消息存储过程
if (object_id(‘proc_error_info’) is not null)
drop procedure proc_error_info
go
create proc proc_error_info
as
select
error_number() ‘错误编号’,
error_message() ‘错误消息’,
error_severity() ‘严重性’,
error_state() ‘状态好’,
error_line() ‘错误行号’,
error_procedure() ‘错误对象(存储过程或触发器)名称’;
go

 # 示例:用异常处理错误信息

–简单try catch示例
begin try
select 1 / 0;
end try
begin catch
exec proc_error_info; --调用错误消息存储过程
end catch
go

 # 示例:异常能处理的错误信息


–简单try catch示例,无法处理错误
begin try
select * * from student;
end try
begin catch
exec proc_error_info;
end catch
go

–简单try catch示例,不处理错误(不存在的表对象)
begin try
select * from st;
end try
begin catch
exec proc_error_info;
end catch
go

–异常处理,能处理存储过程(触发器)中(不存在表对象)的错误信息
if (object_id(‘proc_select’) is not null)
drop procedure proc_select
go
create proc proc_select
as
select * from st;
go
begin try
exec proc_select;
end try
begin catch
exec proc_error_info;
end catch
go

 异常不能处理编译期的错误,如语法错误。以及重编译造成部分名称对象得不到正确解析的时候所出现的错误。

 # 示例:无法提交的事务

–创建临时用表
if (object_id(‘temp_tab’, ‘u’) is not null)
drop table temp_tab
go
create table temp_tab(
id int primary key identity(100000, 1),
name varchar(200)
)
go

begin try
begin tran;
–没有createTime字段
alter table temp_tab drop column createTime;
commit tran;
end try
begin catch
exec proc_error_info;–显示异常信息
if (xact_state() = -1)
begin
print ‘会话具有活动事务,但出现了致使事务被归类为无法提交的事务的错误。’
+ ‘会话无法提交事务或回滚到保存点;它只能请求完全回滚事务。’
+ ‘会话在回滚事务之前无法执行任何写操作。会话在回滚事务之前只能执行读操作。’
+ ‘事务回滚之后,会话便可执行读写操作并可开始新的事务。’;
end
else if (xact_state() = 0)
begin
print ‘会话没有活动事务。’;
end
else if (xact_state() = 1)
begin
print ‘会话具有活动事务。会话可以执行任何操作,包括写入数据和提交事务。’;
end
end catch
go

 # 示例:处理异常日志信息


—异常、错误信息表
if (object_id(‘errorLog’, ‘U’) is not null)
drop table errorLog
go
create table errorLog(
errorLogID int primary key identity(100, 1), --ErrorLog 行的主键。
errorTime datetime default getDate(), --发生错误的日期和时间。
userName sysname default current_user, --执行发生错误的批处理的用户。
errorNumber int, --发生的错误的错误号。
errorSeverity int, --发生的错误的严重性。
errorState int, --发生的错误的状态号。
errorProcedure nvarchar(126), --发生错误的存储过程或触发器的名称。
errorLine int, --发生错误的行号。
errorMessage nvarchar(4000)
)
go

–存储过程:添加异常日志信息
if (object_id(‘proc_add_exception_log’, ‘p’) is not null)
drop proc proc_add_exception_log
go
create proc proc_add_exception_log(@logId int = 0 output)
as
begin
set nocount on;
set @logId = 0;
begin try
if (error_number() is null)
return;

    if (xact_state() = -1)
    begin
        print '会话具有活动事务,但出现了致使事务被归类为无法提交的事务的错误。'
            + '会话无法提交事务或回滚到保存点;它只能请求完全回滚事务。'
            + '会话在回滚事务之前无法执行任何写操作。会话在回滚事务之前只能执行读操作。'
            + '事务回滚之后,会话便可执行读写操作并可开始新的事务。';
    end
    else if (xact_state() = 0)
    begin
        print '会话没有活动事务。';
    end
    else if (xact_state() = 1)
    begin
        print '会话具有活动事务。会话可以执行任何操作,包括写入数据和提交事务。';
    end
    
    --添加日志信息
    insert into errorLog values(getDate(), 
        current_user, error_number(), 
        error_severity(), error_state(), 
        error_procedure(), 
        error_line(), error_message());
    --设置自增值
    select @logId = @@identity;
end try
begin catch
    print '添加异常日志信息出现错误';
    exec proc_error_info;--显示错误信息
    return -1;
end catch

end
go

—处理异常信息示例
declare @id int;
begin try
begin tran;
–删除带有外键的记录信息
delete classes where id = 1;
commit tran;
end try
begin catch
exec proc_error_info;–显示错误信息
if (xact_state() <> 0)
begin
rollback tran;
end
exec proc_add_exception_log @id output
end catch
select * from errorLog where errorLogID = @id;
go

五:sqlserver 视图的使用

视图
1、 什么是视图
视图就是一个虚拟的数据表,该数据表中的数据记录是有一条查询语句的查询结果得到的。

2、 创建视图准则
    创建视图需要考虑一下准则:
# 视图名称必须遵循标识符的规则,该名称不得与该架构的如何表的名称相同
# 你可以对其他视图创建视图。允许嵌套视图,但嵌套不得超过32层。视图最多可以有1024个字段
# 不能将规则和default定义于视图相关联
# 视图的查询不能包含compute子句、compute by子句或into关键字
# 定义视图的查询不能包含order by子句,除非在select 语句的选择列表中还有top子句

下列情况必须指定视图中每列的名称:
# 视图中的如何列都是从算术表达式、内置函数或常量派生而来
# 视图中有两列或多列具有相同名称(通常由于视图定义包含联接,因此来自两个或多个不同的列具有相同的名称)
# 希望视图中的列指定一个与其原列不同的名称(也可以在视图中重命名列)。无论是否重命名,视图列都回继承原列的数据类型

3、 创建视图

–创建视图
if (exists (select * from sys.objects where name = ‘v_stu’))
drop view v_stu
go
create view v_stu
as
select id, name, age, sex from student;

4、 修改视图

alter view v_stu
as
select id, name, sex from student;

alter view v_stu(编号, 名称, 性别)
as
select id, name, sex from student
go
select * from v_stu;

select * from information_schema.views;

5、 加密视图

–加密视图
if (exists (select * from sys.objects where name = ‘v_student_info’))
drop view v_student_info
go
create view v_student_info
with encryption --加密
as
select id, name, age from student
go
–view_definition is null
select * from information_schema.views
where table_name like ‘v_stu’;

六:sqlserver 事务的使用

Ø 事务
在数据库中有时候需要把多个步骤的指令当作一个整体来运行,这个整体要么全部成功,要么全部失败,这就需要用到事务。
1、 事务的特点
事务有若干条T-SQL指令组成,并且所有的指令昨晚一个整体提交给数据库系统,执行时,这组指令要么全部执行完成,要么全部取消。因此,事务是一个不可分割的逻辑单元。

    事务有4个属性:原子性(Atomicity)、一致性(Consistency)、隔离性(Isolation)以及持久性(Durability),也称作事务的ACID属性。
    原子性:事务内的所有工作要么全部完成,要么全部不完成,不存在只有一部分完成的情况。
    一致性:事务内的然后操作都不能违反数据库的然后约束或规则,事务完成时有内部数据结构都必须是正确的。
    隔离性:事务直接是相互隔离的,如果有两个事务对同一个数据库进行操作,比如读取表数据。任何一个事务看到的所有内容要么是其他事务完成之前的状态,要么是其他事务完成之后的状态。一个事务不可能遇到另一个事务的中间状态。
    持久性:事务完成之后,它对数据库系统的影响是持久的,即使是系统错误,重新启动系统后,该事务的结果依然存在。

2、 事务的模式
    a、 显示事务
    显示事务就是用户使用T-SQL明确的定义事务的开始(begin transaction)和提交(commit transaction)或回滚事务(rollback transaction)
    b、 自动提交事务
    自动提交事务是一种能够自动执行并能自动回滚事务,这种方式是T-SQL的默认事务方式。例如在删除一个表记录的时候,如果这条记录有主外键关系的时候,删除就会受主外键约束的影响,那么这个删除就会取消。
    可以设置事务进入隐式方式:set implicit_transaction on;
    c、 隐式事务
    隐式事务是指当事务提交或回滚后,SQL Server自动开始事务。因此,隐式事务不需要使用begin transaction显示开始,只需直接失业提交事务或回滚事务的T-SQL语句即可。
    使用时,需要设置set implicit_transaction on语句,将隐式事务模式打开,下一个语句会启动一个新的事物,再下一个语句又将启动一个新事务。

3、 事务处理
    常用T-SQL事务语句:
    a、 begin transaction语句
    开始事务,而@@trancount全局变量用来记录事务的数目值加1,可以用@@error全局变量记录执行过程中的错误信息,如果没有错误可以直接提交事务,有错误可以回滚。
    b、 commit transaction语句
    回滚事务,表示一个隐式或显示的事务的结束,对数据库所做的修改正式生效。并将@@trancount的值减1;
    c、 rollback transaction语句
    回滚事务,执行rollback tran语句后,数据会回滚到begin tran的时候的状态

4、 事务的示例
--******************************事务sql***********************************

—开启事务
begin tran
–错误扑捉机制,看好啦,这里也有的。并且可以嵌套。
begin try
–语句正确
insert into [Company] (Name,CreateTime,CreatorId) values (‘阿里巴巴集团’,‘2019-03-20’,1)
–CreatorId为int类型,出错
insert into [Company] (Name,CreateTime,CreatorId) values (‘百度科技有限公司’,‘2019-03-20’,‘Test’)
–语句正确
insert into [Company] (Name,CreateTime,CreatorId) values (‘腾讯科技有限公司’,‘2019-03-20’,2)
end try
begin catch
select Error_number() as ErrorNumber, --错误代码
Error_severity() as ErrorSeverity, --错误严重级别,级别小于10 try catch 捕获不到
Error_state() as ErrorState , --错误状态码
Error_Procedure() as ErrorProcedure , --出现错误的存储过程或触发器的名称。
Error_line() as ErrorLine, --发生错误的行号
Error_message() as ErrorMessage --错误的具体信息
if(@@trancount>0) --全局变量@@trancount,事务开启此值+1,他用来判断是有开启事务
rollback tran —由于出错,这里回滚到开始,第一条语句也没有插入成功。
end catch
if(@@trancount>0)
commit tran --如果成功Company表中,将会有3条数据。

–表本身为空表,ID ,Numb为int 类型,其它为nvarchar类型
select * from [Company]

默认开启事务*****

死锁sql***
begin tran
update [SysUser] set Name=‘腾讯公司-003’ where Id=9;
waitfor delay ‘0:0:5’
update [Company] set Name=‘测试’ where Id=2;
commit tran

begin tran
update [Company] set Name=‘腾讯公司001’ where Id=2;
waitfor delay ‘0:0:5’
update [SysUser] set Name=‘测试-001’ where Id=9;
commit tran

事务隔离read uncommitted***
begin tran
set deadlock_priority low
update Company set Name=‘软谋234’ where Id=1
waitfor delay ‘0:0:5’ --等待5秒执行下面的语句
rollback tran

set tran isolation level read uncommitted
select * from [Company] where id=1 --读取的数据为正在修改的数据 ,脏读
waitfor delay ‘0:0:5’ --5秒之后数据已经回滚
select * from [Company] where id=1–回滚之后的数据

事务含save tran*****

—开启事务
begin tran
–错误扑捉机制,看好啦,这里也有的。并且可以嵌套。
begin try
–语句正确
insert into [Company] (Name,CreateTime,CreatorId) values (‘软谋’,‘2019-03-20’,3)
–加入保存点
save tran SavePoint
–CreatorId为int类型,出错
insert into [Company] (Name,CreateTime,CreatorId) values (‘软谋’,‘2019-03-20’,‘Test’)
–语句正确
insert into [Company] (Name,CreateTime,CreatorId) values (‘软谋’,‘2019-03-20’,4)
end try
begin catch
select Error_number() as ErrorNumber, --错误代码
Error_severity() as ErrorSeverity, --错误严重级别,级别小于10 try catch 捕获不到
Error_state() as ErrorState , --错误状态码
Error_Procedure() as ErrorProcedure , --出现错误的存储过程或触发器的名称。
Error_line() as ErrorLine, --发生错误的行号
Error_message() as ErrorMessage --错误的具体信息
if(@@trancount>0) --全局变量@@trancount,事务开启此值+1,他用来判断是有开启事务
rollback tran —由于出错,这里回滚到开始,第一条语句也没有插入成功。
end catch
if(@@trancount>0)
rollback tran SavePoint --如果成功Company表中,将会有3条数据。

–表本身为空表,ID ,Numb为int 类型,其它为nvarchar类型
select * from [Company]


锁定提示 描述
HOLDLOCK 将共享锁保留到事务完成,而不是在相应的表、行或数据页不再需要时就立即释放锁。HOLDLOCK 等同于 SERIALIZABLE。
NOLOCK 不要发出共享锁,并且不要提供排它锁。当此选项生效时,可能会读取未提交的事务或一组在读取中间回滚的页面。有可能发生脏读。仅应用于SELECT语句。
PAGLOCK 在通常使用单个表锁的地方采用页锁。
READCOMMITTED 用与运行在提交读隔离级别的事务相同的锁语义执行扫描。默认情况下,SQL Server 2000 在此隔离级别上操作。
READPAST 跳过锁定行。此选项导致事务跳过由其它事务锁定的行(这些行平常会显示在结果集内),而不是阻塞该事务,使其等待其它事务释放在这些行上的锁。READPAST 锁提示仅适用于运行在提交读隔离级别的事务,并且只在行级锁之后读取。仅适用于 SELECT 语句。
READUNCOMMITTED 等同于 NOLOCK。
REPEATABLEREAD 用与运行在可重复读隔离级别的事务相同的锁语义执行扫描。
ROWLOCK 使用行级锁,而不使用粒度更粗的页级锁和表级锁。 (SELECT,UPDATE和DELETE)
SERIALIZABLE 用与运行在可串行读隔离级别的事务相同的锁语义执行扫描。等同于 HOLDLOCK。
TABLOCK 使用表锁代替粒度更细的行级锁或页级锁。在语句结束前,SQL Server 一直持有该锁。但是,如果同时指定 HOLDLOCK,那么在事务结束之前,锁将被一直持有。
TABLOCKX 使用表的排它锁。该锁可以防止其它事务读取或更新表,并在语句或事务结束前一直持有。
UPDLOCK 读取表时使用更新锁,而不使用共享锁,并将锁一直保留到语句或事务的结束。UPDLOCK 的优点是允许您读取数据(不阻塞其它事务)并在以后更新数据,同时确保自从上次读取数据后数据没有被更改。
XLOCK 使用排它锁并一直保持到由语句处理的所有数据上的事务结束时。可以使用 PAGLOCK 或 TABLOCK 指定该锁,这种情况下排它锁适用于适当级别的粒度

七:sqlserver 各种查询语法

基本常用查询
–select
select * from student;

–all 查询所有
select all sex from student;

–distinct 过滤重复
select distinct sex from student;

–count 统计
select count(*) from student;
select count(sex) from student;
select count(distinct sex) from student;

–top 取前N条记录
select top 3 * from student;

–alias column name 列重命名
select id as 编号, name ‘名称’, sex 性别 from student;

–alias table name 表重命名
select id, name, s.id, s.name from student s;

–column 列运算
select (age + id) col from student;
select s.name + ‘-’ + c.name from classes c, student s where s.cid = c.id;

–where 条件
select * from student where id = 2;
select * from student where id > 7;
select * from student where id < 3;
select * from student where id <> 3;
select * from student where id >= 3;
select * from student where id <= 5;
select * from student where id !> 3;
select * from student where id !< 5;

–and 并且
select * from student where id > 2 and sex = 1;

–or 或者
select * from student where id = 2 or sex = 1;

–between … and … 相当于并且
select * from student where id between 2 and 5;
select * from student where id not between 2 and 5;

–like 模糊查询
select * from student where name like ‘%a%’;
select * from student where name like ‘%[a][o]%’;
select * from student where name not like ‘%a%’;
select * from student where name like ‘ja%’;
select * from student where name not like ‘%[j,n]%’;
select * from student where name like ‘%[j,n,a]%’;
select * from student where name like ‘%[^ja,as,on]%’;
select * from student where name like ‘%[ja_on]%’;

–in 子查询
select * from student where id in (1, 2);

–not in 不在其中
select * from student where id not in (1, 2);

–is null 是空
select * from student where age is null;

–is not null 不为空
select * from student where age is not null;

–order by 排序
select * from student order by name;
select * from student order by name desc;
select * from student order by name asc;

–group by 分组
按照年龄进行分组统计
select count(age), age from student group by age;
按照性别进行分组统计
select count(), sex from student group by sex;
按照年龄和性别组合分组统计,并排序
select count(
), sex from student group by sex, age order by age;
按照性别分组,并且是id大于2的记录最后按照性别排序
select count(), sex from student where id > 2 group by sex order by sex;
查询id大于2的数据,并完成运算后的结果进行分组和排序
select count(
), (sex * id) new from student where id > 2 group by sex * id order by sex * id;

–group by all 所有分组
按照年龄分组,是所有的年龄
select count(*), age from student group by all age;

–having 分组过滤条件
按照年龄分组,过滤年龄为空的数据,并且统计分组的条数和现实年龄信息
select count(*), age from student group by age having age is not null;

按照年龄和cid组合分组,过滤条件是cid大于1的记录
select count(*), cid, sex from student group by cid, sex having cid > 1;

按照年龄分组,过滤条件是分组后的记录条数大于等于2
select count(*), age from student group by age having count(age) >= 2;

按照cid和性别组合分组,过滤条件是cid大于1,cid的最大值大于2
select count(*), cid, sex from student group by cid, sex having cid > 1 and max(cid) > 2;
Ø 嵌套子查询
子查询是一个嵌套在select、insert、update或delete语句或其他子查询中的查询。任何允许使用表达式的地方都可以使用子查询。子查询也称为内部查询或内部选择,而包含子查询的语句也成为外部查询或外部选择。

from (select … table)示例

将一个table的查询结果当做一个新表进行查询
select * from (
select id, name from student where sex = 1
) t where t.id > 2;
上面括号中的语句,就是子查询语句(内部查询)。在外面的是外部查询,其中外部查询可以包含以下语句:
1、 包含常规选择列表组件的常规select查询
2、 包含一个或多个表或视图名称的常规from语句
3、 可选的where子句
4、 可选的group by子句
5、 可选的having子句

示例

查询班级信息,统计班级学生人生
select , (select count() from student where cid = classes.id) as num
from classes order by num;

in, not in子句查询示例

查询班级id大于小于的这些班级的学生信息
select * from student where cid in (
select id from classes where id > 2 and id < 4
);

查询不是班的学生信息
select * from student where cid not in (
select id from classes where name = ‘2班’
)
in、not in 后面的子句返回的结果必须是一列,这一列的结果将会作为查询条件对应前面的条件。如cid对应子句的id;

exists和not exists子句查询示例

查询存在班级id为的学生信息
select * from student where exists (
select * from classes where id = student.cid and id = 3
);

查询没有分配班级的学生信息
select * from student where not exists (
select * from classes where id = student.cid
);
exists和not exists查询需要内部查询和外部查询进行一个关联的条件,如果没有这个条件将是查询到的所有信息。如:id等于student.id;

some、any、all子句查询示例

查询班级的学生年龄大于班级的学生的年龄的信息
select * from student where cid = 5 and age > all (
select age from student where cid = 3
);

select * from student where cid = 5 and age > any (
select age from student where cid = 3
);

select * from student where cid = 5 and age > some (
select age from student where cid = 3
);

Ø 聚合查询
1、 distinct去掉重复数据
select distinct sex from student;
select count(sex), count(distinct sex) from student;

2、 compute和compute by汇总查询
对年龄大于的进行汇总
select age from student
where age > 20 order by age compute sum(age) by age;

对年龄大于的按照性别进行分组汇总年龄信息
select id, sex, age from student
where age > 20 order by sex, age compute sum(age) by sex;

按照年龄分组汇总
select age from student
where age > 20 order by age, id compute sum(age);

按照年龄分组,年龄汇总,id找最大值
select id, age from student
where age > 20 order by age compute sum(age), max(id);
compute进行汇总前面是查询的结果,后面一条结果集就是汇总的信息。compute子句中可以添加多个汇总表达式,可以添加的信息如下:
a、 可选by关键字。它是每一列计算指定的行聚合
b、 行聚合函数名称。包括sum、avg、min、max、count等
c、 要对其执行聚合函数的列
compute by适合做先分组后汇总的业务。compute by后面的列一定要是order by中出现的列。

3、 cube汇总
cube汇总和compute效果类似,但语法较简洁,而且返回的是一个结果集。
select count(), sex from student group by sex with cube;
select count(
), age, sum(age) from student where age is not null group by age with cube;
cube要结合group by语句完成分组汇总

Ø 排序函数
排序在很多地方需要用到,需要对查询结果进行排序并且给出序号。比如:
1、 对某张表进行排序,序号需要递增不重复的
2、 对学生的成绩进行排序,得出名次,名次可以并列,但名次的序号是连续递增的
3、 在某些排序的情况下,需要跳空序号,虽然是并列
基本语法
排序函数 over([分组语句] 排序子句[desc][asc])
排序子句 order by 列名, 列名
分组子句 partition by 分组列, 分组列

row_number函数

根据排序子句给出递增连续序号
按照名称排序的顺序递增
select s.id, s.name, cid, c.name, row_number() over(order by c.name) as number
from student s, classes c where cid = c.id;

rank函数函数

根据排序子句给出递增的序号,但是存在并列并且跳空
顺序递增
select id, name, rank() over(order by cid) as rank from student;

跳过相同递增
select s.id, s.name, cid, c.name, rank() over(order by c.name) as rank
from student s, classes c where cid = c.id;

dense_rank函数

根据排序子句给出递增的序号,但是存在并列不跳空
不跳过,直接递增
select s.id, s.name, cid, c.name, dense_rank() over(order by c.name) as dense
from student s, classes c where cid = c.id;

partition by分组子句

可以完成对分组的数据进行增加排序,partition by可以与以上三个函数联合使用。
利用partition by按照班级名称分组,学生id排序
select s.id, s.name, cid, c.name, row_number() over(partition by c.name order by s.id) as rank
from student s, classes c where cid = c.id;

select s.id, s.name, cid, c.name, rank() over(partition by c.name order by s.id) as rank
from student s, classes c where cid = c.id;

select s.id, s.name, cid, c.name, dense_rank() over(partition by c.name order by s.id) as rank
from student s, classes c where cid = c.id;

ntile平均排序函数

将要排序的数据进行平分,然后按照等分排序。ntile中的参数代表分成多少等分。
select s.id, s.name, cid, c.name,
ntile(5) over(order by c.name) as ntile
from student s, classes c where cid = c.id;

Ø 集合运算
操作两组查询结果,进行交集、并集、减集运算
1、 union和union all进行并集运算
–union 并集、不重复
select id, name from student where name like ‘ja%’
union
select id, name from student where id = 4;

–并集、重复
select * from student where name like ‘ja%’
union all
select * from student;

2、 intersect进行交集运算
–交集(相同部分)
select * from student where name like ‘ja%’
intersect
select * from student;

3、 except进行减集运算
–减集(除相同部分)
select * from student where name like ‘ja%’
except
select * from student where name like ‘jas%’;

Ø 公式表表达式
查询表的时候,有时候中间表需要重复使用,这些子查询被重复查询调用,不但效率低,而且可读性低,不利于理解。那么公式表表达式可以解决这个问题。
我们可以将公式表表达式(CET)视为临时结果集,在select、insert、update、delete或是create view语句的执行范围内进行定义。
–表达式
with statNum(id, num) as
(
select cid, count(*)
from student
where id > 0
group by cid
)
select id, num from statNum order by id;

with statNum(id, num) as
(
select cid, count(*)
from student
where id > 0
group by cid
)
select max(id), avg(num) from statNum;

Ø 连接查询
1、 简化连接查询
–简化联接查询
select s.id, s.name, c.id, c.name from student s, classes c where s.cid = c.id;

2、 left join左连接
–左连接
select s.id, s.name, c.id, c.name from student s left join classes c on s.cid = c.id;

3、 right join右连接
–右连接
select s.id, s.name, c.id, c.name from student s right join classes c on s.cid = c.id;

4、 inner join内连接
–内连接
select s.id, s.name, c.id, c.name from student s inner join classes c on s.cid = c.id;

–inner可以省略
select s.id, s.name, c.id, c.name from student s join classes c on s.cid = c.id;

5、 cross join交叉连接
–交叉联接查询,结果是一个笛卡儿乘积
select s.id, s.name, c.id, c.name from student s cross join classes c
–where s.cid = c.id;

6、 自连接(同一张表进行连接查询)
–自连接
select distinct s.* from student s, student s1 where s.id <> s1.id and s.sex = s1.sex;

Ø 函数
1、 聚合函数
max最大值、min最小值、count统计、avg平均值、sum求和、var求方差
select
max(age) max_age,
min(age) min_age,
count(age) count_age,
avg(age) avg_age,
sum(age) sum_age,
var(age) var_age
from student;

2、 日期时间函数
select dateAdd(day, 3, getDate());–加天
select dateAdd(year, 3, getDate());–加年
select dateAdd(hour, 3, getDate());–加小时
–返回跨两个指定日期的日期边界数和时间边界数
select dateDiff(day, ‘2011-06-20’, getDate());
–相差秒数
select dateDiff(second, ‘2011-06-22 11:00:00’, getDate());
–相差小时数
select dateDiff(hour, ‘2011-06-22 10:00:00’, getDate());
select dateName(month, getDate());–当前月份
select dateName(minute, getDate());–当前分钟
select dateName(weekday, getDate());–当前星期
select datePart(month, getDate());–当前月份
select datePart(weekday, getDate());–当前星期
select datePart(second, getDate());–当前秒数
select day(getDate());–返回当前日期天数
select day(‘2011-06-30’);–返回当前日期天数
select month(getDate());–返回当前日期月份
select month(‘2011-11-10’);
select year(getDate());–返回当前日期年份
select year(‘2010-11-10’);
select getDate();–当前系统日期
select getUTCDate();–utc日期

3、 数学函数
select pi();–PI函数
select rand(100), rand(50), rand(), rand();–随机数
select round(rand(), 3), round(rand(100), 5);–精确小数位
–精确位数,负数表示小数点前
select round(123.456, 2), round(254.124, -2);
select round(123.4567, 1, 2);

4、 元数据
select col_name(object_id(‘student’), 1);–返回列名
select col_name(object_id(‘student’), 2);
–该列数据类型长度
select col_length(‘student’, col_name(object_id(‘student’), 2));
–该列数据类型长度
select col_length(‘student’, col_name(object_id(‘student’), 1));
–返回类型名称、类型id
select type_name(type_id(‘varchar’)), type_id(‘varchar’);
–返回列类型长度
select columnProperty(object_id(‘student’), ‘name’, ‘PRECISION’);
–返回列所在索引位置
select columnProperty(object_id(‘student’), ‘sex’, ‘ColumnId’);

5、 字符串函数
select ascii(‘a’);–字符转换ascii值
select ascii(‘A’);
select char(97);–ascii值转换字符
select char(65);
select nchar(65);
select nchar(45231);
select nchar(32993);–unicode转换字符
select unicode(‘A’), unicode(‘中’);–返回unicode编码值
select soundex(‘hello’), soundex(‘world’), soundex(‘word’);
select patindex(’%a’, ‘ta’), patindex(’%ac%’, ‘jack’), patindex(‘dex%’, ‘dexjack’);–匹配字符索引
select ‘a’ + space(2) + ‘b’, ‘c’ + space(5) + ‘d’;–输出空格
select charIndex(‘o’, ‘hello world’);–查找索引
select charIndex(‘o’, ‘hello world’, 6);–查找索引
select quoteName(‘abc[]def’), quoteName(‘123]45’);
–精确数字
select str(123.456, 2), str(123.456, 3), str(123.456, 4);
select str(123.456, 9, 2), str(123.456, 9, 3), str(123.456, 6, 1), str(123.456, 9, 6);
select difference(‘hello’, ‘helloWorld’);–比较字符串相同
select difference(‘hello’, ‘world’);
select difference(‘hello’, ‘llo’);
select difference(‘hello’, ‘hel’);
select difference(‘hello’, ‘hello’);
select replace(‘abcedef’, ‘e’, ‘E’);–替换字符串
select stuff(‘hello world’, 3, 4, ‘ABC’);–指定位置替换字符串
select replicate(‘abc#’, 3);–重复字符串
select subString(‘abc’, 1, 1), subString(‘abc’, 1, 2), subString(‘hello Wrold’, 7, 5);–截取字符串
select len(‘abc’);–返回长度
select reverse(‘sqlServer’);–反转字符串

select left(‘leftString’, 4);–取左边字符串
select left(‘leftString’, 7);
select right(‘leftString’, 6);–取右边字符串
select right(‘leftString’, 3);
select lower(‘aBc’), lower(‘ABC’);–小写
select upper(‘aBc’), upper(‘abc’);–大写
–去掉左边空格
select ltrim(’ abc’), ltrim(’# abc#’), ltrim(’ abc’);
–去掉右边空格
select rtrim(’ abc ‘), rtrim(’# abc# '), rtrim(‘abc’);

6、 安全函数
select current_user;
select user;
select user_id(), user_id(‘dbo’), user_id(‘public’), user_id(‘guest’);
select user_name(), user_name(1), user_name(0), user_name(2);
select session_user;
select suser_id(‘sa’);
select suser_sid(), suser_sid(‘sa’), suser_sid(‘sysadmin’), suser_sid(‘serveradmin’);
select is_member(‘dbo’), is_member(‘public’);
select suser_name(), suser_name(1), suser_name(2), suser_name(3);
select suser_sname(), suser_sname(0x01), suser_sname(0x02), suser_sname(0x03);
select is_srvRoleMember(‘sysadmin’), is_srvRoleMember(‘serveradmin’);
select permissions(object_id(‘student’));
select system_user;
select schema_id(), schema_id(‘dbo’), schema_id(‘guest’);
select schema_name(), schema_name(1), schema_name(2), schema_name(3);

7、 系统函数
select app_name();–当前会话的应用程序名称
select cast(2011 as datetime), cast(‘10’ as money), cast(‘0’ as varbinary);–类型转换
select convert(datetime, ‘2011’);–类型转换
select coalesce(null, ‘a’), coalesce(‘123’, ‘a’);–返回其参数中第一个非空表达式
select collationProperty(‘Traditional_Spanish_CS_AS_KS_WS’, ‘CodePage’);
select current_timestamp;–当前时间戳
select current_user;
select isDate(getDate()), isDate(‘abc’), isNumeric(1), isNumeric(‘a’);
select dataLength(‘abc’);
select host_id();
select host_name();
select db_name();
select ident_current(‘student’), ident_current(‘classes’);–返回主键id的最大值
select ident_incr(‘student’), ident_incr(‘classes’);–id的增量值
select ident_seed(‘student’), ident_seed(‘classes’);
select @@identity;–最后一次自增的值
select identity(int, 1, 1) as id into tab from student;–将studeng表的烈属,以/1自增形式创建一个tab
select * from tab;
select @@rowcount;–影响行数
select @@cursor_rows;–返回连接上打开的游标的当前限定行的数目
select @@error;–T-SQL的错误号
select @@procid;

8、 配置函数
set datefirst 7;–设置每周的第一天,表示周日
select @@datefirst as ‘星期的第一天’, datepart(dw, getDate()) AS ‘今天是星期’;
select @@dbts;–返回当前数据库唯一时间戳
set language ‘Italian’;
select @@langId as ‘Language ID’;–返回语言id
select @@language as ‘Language Name’;–返回当前语言名称
select @@lock_timeout;–返回当前会话的当前锁定超时设置(毫秒)
select @@max_connections;–返回SQL Server 实例允许同时进行的最大用户连接数
select @@MAX_PRECISION AS ‘Max Precision’;–返回decimal 和numeric 数据类型所用的精度级别
select @@SERVERNAME;–SQL Server 的本地服务器的名称
select @@SERVICENAME;–服务名
select @@SPID;–当前会话进程id
select @@textSize;
select @@version;–当前数据库版本信息

9、 系统统计函数
select @@CONNECTIONS;–连接数
select @@PACK_RECEIVED;
select @@CPU_BUSY;
select @@PACK_SENT;
select @@TIMETICKS;
select @@IDLE;
select @@TOTAL_ERRORS;
select @@IO_BUSY;
select @@TOTAL_READ;–读取磁盘次数
select @@PACKET_ERRORS;–发生的网络数据包错误数
select @@TOTAL_WRITE;–sqlserver执行的磁盘写入次数
select patIndex(’%soft%’, ‘microsoft SqlServer’);
select patIndex(‘soft%’, ‘software SqlServer’);
select patIndex(’%soft’, ‘SqlServer microsoft’);
select patIndex(’%so_gr%’, ‘Jsonisprogram’);

10、 用户自定义函数

查看当前数据库所有函数

–查询所有已创建函数
select definition,* from sys.sql_modules m join sys.objects o on m.object_id = o.object_id
and type in(‘fn’, ‘if’, ‘tf’);

创建函数

if (object_id(‘fun_add’, ‘fn’) is not null)
drop function fun_add
go
create function fun_add(@num1 int, @num2 int)
returns int
with execute as caller
as
begin
declare @result int;
if (@num1 is null)
set @num1 = 0;
if (@num2 is null)
set @num2 = 0;
set @result = @num1 + @num2;
return @result;
end
go
调用函数
select dbo.fun_add(id, age) from student;

–自定义函数,字符串连接
if (object_id(‘fun_append’, ‘fn’) is not null)
drop function fun_append
go
create function fun_append(@args nvarchar(1024), @args2 nvarchar(1024))
returns nvarchar(2048)
as
begin
return @args + @args2;
end
go

select dbo.fun_append(name, ‘abc’) from student;

修改函数

alter function fun_append(@args nvarchar(1024), @args2 nvarchar(1024))
returns nvarchar(1024)
as
begin
declare @result varchar(1024);
–coalesce返回第一个不为null的值
set @args = coalesce(@args, ‘’);
set @args2 = coalesce(@args2, ‘’);;
set @result = @args + @args2;
return @result;
end
go

select dbo.fun_append(name, ‘#abc’) from student;

返回table类型函数

–返回table对象函数
select name, object_id, type from sys.objects where type in (‘fn’, ‘if’, ‘tf’) or type like ‘%f%’;

if (exists (select * from sys.objects where type in (‘fn’, ‘if’, ‘tf’) and name = ‘fun_find_stuRecord’))
drop function fun_find_stuRecord
go
create function fun_find_stuRecord(@id int)
returns table
as
return (select * from student where id = @id);
go

select * from dbo.fun_find_stuRecord(2);

八:sqlserver 存储过程的使用

Transact-SQL中的存储过程,非常类似于Java语言中的方法,它可以重复调用。当存储过程执行一次后,可以将语句缓存中,这样下次执行的时候直接使用缓存中的语句。这样就可以提高存储过程的性能。
Ø 存储过程的概念
存储过程Procedure是一组为了完成特定功能的SQL语句集合,经编译后存储在数据库中,用户通过指定存储过程的名称并给出参数来执行。
存储过程中可以包含逻辑控制语句和数据操纵语句,它可以接受参数、输出参数、返回单个或多个结果集以及返回值。
由于存储过程在创建时即在数据库服务器上进行了编译并存储在数据库中,所以存储过程运行要比单个的SQL语句块要快。同时由于在调用时只需用提供存储过程名和必要的参数信息,所以在一定程度上也可以减少网络流量、简单网络负担。

1、 存储过程的优点
    A、 存储过程允许标准组件式编程
    存储过程创建后可以在程序中被多次调用执行,而不必重新编写该存储过程的SQL语句。而且数据库专业人员可以随时对存储过程进行修改,但对应用程序源代码却毫无影响,从而极大的提高了程序的可移植性。
    B、 存储过程能够实现较快的执行速度
    如果某一操作包含大量的T-SQL语句代码,分别被多次执行,那么存储过程要比批处理的执行速度快得多。因为存储过程是预编译的,在首次运行一个存储过程时,查询优化器对其进行分析、优化,并给出最终被存在系统表中的存储计划。而批处理的T-SQL语句每次运行都需要预编译和优化,所以速度就要慢一些。
    C、 存储过程减轻网络流量
    对于同一个针对数据库对象的操作,如果这一操作所涉及到的T-SQL语句被组织成一存储过程,那么当在客户机上调用该存储过程时,网络中传递的只是该调用语句,否则将会是多条SQL语句。从而减轻了网络流量,降低了网络负载。
    D、 存储过程可被作为一种安全机制来充分利用
    系统管理员可以对执行的某一个存储过程进行权限限制,从而能够实现对某些数据访问的限制,避免非授权用户对数据的访问,保证数据的安全。

Ø 系统存储过程
系统存储过程是系统创建的存储过程,目的在于能够方便的从系统表中查询信息或完成与更新数据库表相关的管理任务或其他的系统管理任务。系统存储过程主要存储在master数据库中,以“sp”下划线开头的存储过程。尽管这些系统存储过程在master数据库中,但我们在其他数据库还是可以调用系统存储过程。有一些系统存储过程会在创建新的数据库的时候被自动创建在当前数据库中。
常用系统存储过程有:
exec sp_databases; --查看数据库
exec sp_tables; --查看表
exec sp_columns student;–查看列
exec sp_helpIndex student;–查看索引
exec sp_helpConstraint student;–约束
exec sp_stored_procedures;
exec sp_helptext ‘sp_stored_procedures’;–查看存储过程创建、定义语句
exec sp_rename student, stuInfo;–修改表、索引、列的名称
exec sp_renamedb myTempDB, myDB;–更改数据库名称
exec sp_defaultdb ‘master’, ‘myDB’;–更改登录名的默认数据库
exec sp_helpdb;–数据库帮助,查询数据库信息
exec sp_helpdb master;

系统存储过程示例:

–表重命名
exec sp_rename ‘stu’, ‘stud’;
select * from stud;
–列重命名
exec sp_rename ‘stud.name’, ‘sName’, ‘column’;
exec sp_help ‘stud’;
–重命名索引
exec sp_rename N’student.idx_cid’, N’idx_cidd’, N’index’;
exec sp_help ‘student’;

–查询所有存储过程
select * from sys.objects where type = ‘P’;
select * from sys.objects where type_desc like ‘%pro%’ and name like ‘sp%’;

Ø 用户自定义存储过程
1、 创建语法
create proc | procedure pro_name
[{@参数数据类型} [=默认值] [output],
{@参数数据类型} [=默认值] [output],

]
as
SQL_statements

2、 创建不带参数存储过程
–创建存储过程
if (exists (select * from sys.objects where name = ‘proc_get_student’))
drop proc proc_get_student
go
create proc proc_get_student
as
select * from student;

–调用、执行存储过程
exec proc_get_student;

3、 修改存储过程
–修改存储过程
alter proc proc_get_student
as
select * from student;

4、 带参存储过程
–带参存储过程
if (object_id(‘proc_find_stu’, ‘P’) is not null)
drop proc proc_find_stu
go
create proc proc_find_stu(@startId int, @endId int)
as
select * from student where id between @startId and @endId
go

exec proc_find_stu 2, 4;

5、 带通配符参数存储过程
–带通配符参数存储过程
if (object_id(‘proc_findStudentByName’, ‘P’) is not null)
drop proc proc_findStudentByName
go
create proc proc_findStudentByName(@name varchar(20) = ‘%j%’, @nextName varchar(20) = ‘%’)
as
select * from student where name like @name and name like @nextName;
go

exec proc_findStudentByName;
exec proc_findStudentByName ‘%o%’, ‘t%’;

6、 带输出参数存储过程
if (object_id(‘proc_getStudentRecord’, ‘P’) is not null)
drop proc proc_getStudentRecord
go
create proc proc_getStudentRecord(
@id int, --默认输入参数
@name varchar(20) out, --输出参数
@age varchar(20) output–输入输出参数
)
as
select @name = name, @age = age from student where id = @id and sex = @age;
go


declare @id int,
@name varchar(20),
@temp varchar(20);
set @id = 7;
set @temp = 1;
exec proc_getStudentRecord @id, @name out, @temp output;
select @name, @temp;
print @name + ‘#’ + @temp;

7、 不缓存存储过程
–WITH RECOMPILE 不缓存
if (object_id(‘proc_temp’, ‘P’) is not null)
drop proc proc_temp
go
create proc proc_temp
with recompile
as
select * from student;
go

exec proc_temp;

8、 加密存储过程
–加密WITH ENCRYPTION
if (object_id(‘proc_temp_encryption’, ‘P’) is not null)
drop proc proc_temp_encryption
go
create proc proc_temp_encryption
with encryption
as
select * from student;
go

exec proc_temp_encryption;
exec sp_helptext ‘proc_temp’;
exec sp_helptext ‘proc_temp_encryption’;

9、 带游标参数存储过程
if (object_id(‘proc_cursor’, ‘P’) is not null)
drop proc proc_cursor
go
create proc proc_cursor
@cur cursor varying output
as
set @cur = cursor forward_only static for
select id, name, age from student;
open @cur;
go
–调用
declare @exec_cur cursor;
declare @id int,
@name varchar(20),
@age int;
exec proc_cursor @cur = @exec_cur output;–调用存储过程
fetch next from @exec_cur into @id, @name, @age;
while (@@fetch_status = 0)
begin
fetch next from @exec_cur into @id, @name, @age;
print 'id: ’ + convert(varchar, @id) + ', name: ’ + @name + ', age: ’ + convert(char, @age);
end
close @exec_cur;
deallocate @exec_cur;–删除游标

10、 分页存储过程
—存储过程、row_number完成分页
if (object_id(‘pro_page’, ‘P’) is not null)
drop proc proc_cursor
go
create proc pro_page
@startIndex int,
@endIndex int
as
select count(*) from product
;
select * from (
select row_number() over(order by pid) as rowId, * from product
) temp
where temp.rowId between @startIndex and @endIndex
go
–drop proc pro_page
exec pro_page 1, 4

–分页存储过程
if (object_id(‘pro_page’, ‘P’) is not null)
drop proc pro_stu
go
create procedure pro_stu(
@pageIndex int,
@pageSize int
)
as
declare @startRow int, @endRow int
set @startRow = (@pageIndex - 1) * @pageSize +1
set @endRow = @startRow + @pageSize -1
select * from (
select *, row_number() over (order by id asc) as number from student
) t
where t.number between @startRow and @endRow;

exec pro_stu 2, 2;

Ø Raiserror
Raiserror返回用户定义的错误信息,可以指定严重级别,设置系统变量记录所发生的错误。
语法如下:
Raiserror({msg_id | msg_str | @local_variable}
{, severity, state}
[,argument[,…n]]
[with option[,…n]]
)

msg_id:在sysmessages系统表中指定的用户定义错误信息

msg_str:用户定义的信息,信息最大长度在2047个字符。

severity:用户定义与该消息关联的严重级别。当使用msg_id引发使用sp_addmessage创建的用户定义消息时,raiserror上指定严重性将覆盖sp_addmessage中定义的严重性。

任何用户可以指定0-18直接的严重级别。只有sysadmin固定服务器角色常用或具有alter trace权限的用户才能指定19-25直接的严重级别。19-25之间的安全级别需要使用with log选项。

state:介于1至127直接的任何整数。State默认值是1。

raiserror(‘is error’, 16, 1);
select * from sys.messages;
–使用sysmessages中定义的消息
raiserror(33003, 16, 1);
raiserror(33006, 16, 1);

详细使用的sql:

–exec dbo.Pro_GetPageData ‘Tencent_Subject_001’,’*’,‘20’,‘2’,’’,‘Id’,‘1’

–如果遇到有存储过程Pro_GetPageData 就先删除掉
if exists (select * from sysobjects where type = ‘P’ and name = ‘Pro_GetPageData’)
drop procedure dbo.spStockTakingPaperList;
GO

–创建存储过程
CREATE PROCEDURE [dbo].[Pro_GetPageData]
(
@TableName nvarchar(3000), – 表名
@ReturnFields nvarchar(3000) = ‘*’, – 需要返回的列
@PageSize int = 10, – 每页记录数
@PageIndex int = 0, – 当前页码
@Where nvarchar(3000) = ‘’, – 查询条件
@OrderBy nvarchar(200), – 排序字段名 最好为唯一主键
@OrderType int = 1 – 排序类型 1:降序 其它为升序
)
AS
DECLARE @TotalRecord int
DECLARE @TotalPage int
DECLARE @CurrentPageSize int
DECLARE @TotalRecordForPageIndex int
declare @CountSql nvarchar(4000)

 if @OrderType = 1 
     BEGIN 
         set @OrderBy = ' Order by ' + REPLACE(@OrderBy,',',' desc,') + ' desc ' 
     END 
 else 
     BEGIN 
         set @OrderBy = ' Order by ' + REPLACE(@OrderBy,',',' asc,') + ' asc '    
     END 
 -- 总记录 
 set @CountSql='SELECT @TotalRecord=Count(*) From '+@TableName+' '+@Where 
 execute sp_executesql @CountSql,N'@TotalRecord int out',@TotalRecord out 
 SET @TotalPage=(@TotalRecord-1)/@PageSize+1 
 -- 查询页数不得大于总页数 
 if(@PageIndex > @TotalPage) 
     set @PageIndex = @TotalPage 
 SET @CurrentPageSize=(@PageIndex-1)*@PageSize

 -- 返回记录

 set @TotalRecordForPageIndex=@PageIndex*@PageSize

 exec    ('SELECT *

         FROM (SELECT TOP '+@TotalRecordForPageIndex+' '+@ReturnFields+', ROW_NUMBER() OVER ('+@OrderBy+') AS ROWNUM

         FROM '+@TableName+ ' ' + @Where +' ) AS TempTable 
         WHERE TempTable.ROWNUM >  
         '+@CurrentPageSize) 
 -- 返回总页数和总记录 
 SELECT @TotalPage as PageCount,@TotalRecord as RecordCount

九:sqlserver 触发器的使用

触发器是一种特殊类型的存储过程,它不同于之前的我们介绍的存储过程。触发器主要是通过事件进行触发被自动调用执行的。而存储过程可以通过存储过程的名称被调用。
Ø 什么是触发器
触发器对表进行插入、更新、删除的时候会自动执行的特殊存储过程。触发器一般用在check约束更加复杂的约束上面。触发器和普通的存储过程的区别是:触发器是当对某一个表进行操作。诸如:update、insert、delete这些操作的时候,系统会自动调用执行该表上对应的触发器。SQL Server 2005中触发器可以分为两类:DML触发器和DDL触发器,其中DDL触发器它们会影响多种数据定义语言语句而激发,这些语句有create、alter、drop语句。

DML触发器分为:
1、 after触发器(之后触发)
    a、 insert触发器
    b、 update触发器
    c、 delete触发器

2、 instead of 触发器 (之前触发)

其中after触发器要求只有执行某一操作insert、update、delete之后触发器才被触发,且只能定义在表上。而instead of触发器表示并不执行其定义的操作(insert、update、delete)而仅是执行触发器本身。既可以在表上定义instead of触发器,也可以在视图上定义。

触发器有两个特殊的表:插入表(instered表)和删除表(deleted表)。这两张是逻辑表也是虚表。有系统在内存中创建者两张表,不会存储在数据库中。而且两张表的都是只读的,只能读取数据而不能修改数据。这两张表的结果总是与被改触发器应用的表的结构相同。当触发器完成工作后,这两张表就会被删除。Inserted表的数据是插入或是修改后的数据,而deleted表的数据是更新前的或是删除的数据。

对表的操作 Inserted逻辑表 Deleted逻辑表
增加记录(insert) 存放增加的记录 无
删除记录(delete) 无 存放被删除的记录
修改记录(update) 存放更新后的记录 存放更新前的记录
Update数据的时候就是先删除表记录,然后增加一条记录。这样在inserted和deleted表就都有update后的数据记录了。注意的是:触发器本身就是一个事务,所以在触发器里面可以对修改数据进行一些特殊的检查。如果不满足可以利用事务回滚,撤销操作。

Ø 创建触发器
语法
create trigger tgr_name
on table_name
with encrypion –加密触发器
for update…
as
Transact-SQL

# 创建insert类型触发器

–创建insert插入类型触发器
if (object_id(‘tgr_classes_insert’, ‘tr’) is not null)
drop trigger tgr_classes_insert
go
create trigger tgr_classes_insert
on classes
for insert --插入触发
as
–定义变量
declare @id int, @name varchar(20), @temp int;
–在inserted表中查询已经插入记录信息
select @id = id, @name = name from inserted;
set @name = @name + convert(varchar, @id);
set @temp = @id / 2;
insert into student values(@name, 18 + @id, @temp, @id);
print ‘添加学生成功!’;
go
–插入数据
insert into classes values(‘5班’, getDate());
–查询数据
select * from classes;
select * from student order by id;
insert触发器,会在inserted表中添加一条刚插入的记录。

# 创建delete类型触发器

–delete删除类型触发器
if (object_id(‘tgr_classes_delete’, ‘TR’) is not null)
drop trigger tgr_classes_delete
go
create trigger tgr_classes_delete
on classes
for delete --删除触发
as
print ‘备份数据中……’;
if (object_id(‘classesBackup’, ‘U’) is not null)
–存在classesBackup,直接插入数据
insert into classesBackup select name, createDate from deleted;
else
–不存在classesBackup创建再插入
select * into classesBackup from deleted;
print ‘备份数据成功!’;
go

–不显示影响行数
–set nocount on;
delete classes where name = ‘5班’;
–查询数据
select * from classes;
select * from classesBackup;
delete触发器会在删除数据的时候,将刚才删除的数据保存在deleted表中。

# 创建update类型触发器

–update更新类型触发器
if (object_id(‘tgr_classes_update’, ‘TR’) is not null)
drop trigger tgr_classes_update
go
create trigger tgr_classes_update
on classes
for update
as
declare @oldName varchar(20), @newName varchar(20);
–更新前的数据
select @oldName = name from deleted;
if (exists (select * from student where name like ‘%’+ @oldName + ‘%’))
begin
–更新后的数据
select @newName = name from inserted;
update student set name = replace(name, @oldName, @newName) where name like ‘%’+ @oldName + ‘%’;
print ‘级联修改数据成功!’;
end
else
print ‘无需修改student表!’;
go
–查询数据
select * from student order by id;
select * from classes;
update classes set name = ‘五班’ where name = ‘5班’;
update触发器会在更新数据后,将更新前的数据保存在deleted表中,更新后的数据保存在inserted表中。

# update更新列级触发器

if (object_id(‘tgr_classes_update_column’, ‘TR’) is not null)
drop trigger tgr_classes_update_column
go
create trigger tgr_classes_update_column
on classes
for update
as
–列级触发器:是否更新了班级创建时间
if (update(createDate))
begin
raisError(‘系统提示:班级创建时间不能修改!’, 16, 11);
rollback tran;
end
go
–测试
select * from student order by id;
select * from classes;
update classes set createDate = getDate() where id = 3;
update classes set name = ‘四班’ where id = 7;
更新列级触发器可以用update是否判断更新列记录;

# instead of类型触发器
   instead of触发器表示并不执行其定义的操作(insert、update、delete)而仅是执行触发器本身的内容。
   创建语法

create trigger tgr_name
on table_name
with encryption
instead of update…
as
T-SQL

  # 创建instead of触发器

if (object_id(‘tgr_classes_inteadOf’, ‘TR’) is not null)
drop trigger tgr_classes_inteadOf
go
create trigger tgr_classes_inteadOf
on classes
instead of delete/, update, insert/
as
declare @id int, @name varchar(20);
–查询被删除的信息,病赋值
select @id = id, @name = name from deleted;
print 'id: ’ + convert(varchar, @id) + ', name: ’ + @name;
–先删除student的信息
delete student where cid = @id;
–再删除classes的信息
delete classes where id = @id;
print '删除[ id: ’ + convert(varchar, @id) + ‘, name: ’ + @name + ’ ] 的信息成功!’;
go
–test
select * from student order by id;
select * from classes;
delete classes where id = 7;

  # 显示自定义消息raiserror

if (object_id(‘tgr_message’, ‘TR’) is not null)
drop trigger tgr_message
go
create trigger tgr_message
on student
after insert, update
as raisError(‘tgr_message触发器被触发’, 16, 10);
go
–test
insert into student values(‘lily’, 22, 1, 7);
update student set sex = 0 where name = ‘lucy’;
select * from student order by id;

# 修改触发器

alter trigger tgr_message
on student
after delete
as raisError(‘tgr_message触发器被触发’, 16, 10);
go
–test
delete from student where name = ‘lucy’;

# 启用、禁用触发器

–禁用触发器
disable trigger tgr_message on student;
–启用触发器
enable trigger tgr_message on student;

# 查询创建的触发器信息

–查询已存在的触发器
select * from sys.triggers;
select * from sys.objects where type = ‘TR’;

–查看触发器触发事件
select te.* from sys.trigger_events te join sys.triggers t
on t.object_id = te.object_id
where t.parent_class = 0 and t.name = ‘tgr_valid_data’;

–查看创建触发器语句
exec sp_helptext ‘tgr_message’;

# 示例,验证插入数据

if ((object_id(‘tgr_valid_data’, ‘TR’) is not null))
drop trigger tgr_valid_data
go
create trigger tgr_valid_data
on student
after insert
as
declare @age int,
@name varchar(20);
select @name = s.name, @age = s.age from inserted s;
if (@age < 18)
begin
raisError(‘插入新数据的age有问题’, 16, 1);
rollback tran;
end
go
–test
insert into student values(‘forest’, 2, 0, 7);
insert into student values(‘forest’, 22, 0, 7);
select * from student order by id;

# 示例,操作日志

if (object_id(‘log’, ‘U’) is not null)
drop table log
go
create table log(
id int identity(1, 1) primary key,
action varchar(20),
createDate datetime default getDate()
)
go
if (exists (select * from sys.objects where name = ‘tgr_student_log’))
drop trigger tgr_student_log
go
create trigger tgr_student_log
on student
after insert, update, delete
as
if ((exists (select 1 from inserted)) and (exists (select 1 from deleted)))
begin
insert into log(action) values(‘updated’);
end
else if (exists (select 1 from inserted) and not exists (select 1 from deleted))
begin
insert into log(action) values(‘inserted’);
end
else if (not exists (select 1 from inserted) and exists (select 1 from deleted))
begin
insert into log(action) values(‘deleted’);
end
go
–test
insert into student values(‘king’, 22, 1, 7);
update student set sex = 0 where name = ‘king’;
delete student where name = ‘king’;
select * from log;
select * from student order by id;

十:sqlserver 表分区

请看如下链接
http://www.cnblogs.com/knowledgesea/p/3696912.html

十一:sqlserver 主从数据库同步读写分离

请看如下链接
http://www.it165.net/database/html/201306/4088.html

十二:sqlserver 数据库总结和优化

命名风格:	大写字母的模块缩写,不要下划线(避免映射),英文单词,首字母大写								
	拼音/汉字完全反对								
									
主键只是唯一标识,主键一般对用户没有意义;主键最好单例,提升查询效率;									
复合索引(mapping/几个外键组合)									
永不更新,数据不要变化;最好由计算机生成									
									
自增ID	数据库自动增加,int/bigint,sqlserver默认聚集索引,空间小,可以有业务意义(比如大于1000w都是新用户)								
	多库环境、不同环境的数据库id冲突; 订单连续,容易让同行推算出你的销量;								
GUID	GUID程序生成的,全球唯一,插入数据库,不会错误的join,无限的,方便导入								
	空间大,没有自身含义,没有聚集索引(创建时间来聚集)								
									
外键	描述数据关系的,规范数据关系								
	外键做数据校验,级联删除(其实现在都是假删除)								
	有严格数据关系的时候,使用外键								
	导入麻烦、增删改的数据库多一步操作,								
	更多的是通过程序来完成,虚拟外键								
	合理使用:尽量少的使用外键;大型互联网项目瓶颈一般都在数据库,尽量少的让数据库做事儿;								
		如果数据严谨性要求很高,可以用外键;其他的就不怎么用了,尤其是互联网项目							
															
1 数据库事务和数据库锁									
2 存储过程、触发器、游标、视图、自定义函数									
3 字段类型、字段可空、统计字段、逻辑删除									
														
数据库事务	多条sql作为一个整体提交给数据库系统,要么全部执行完成,要么全部取消。是一个不可分割的逻辑单元。								
	两个sql语句,一个下订单成功;另一个减掉库存;(事务保证一起成功或者一起失败)								
	"update [Company] SET Name='软谋',CreatorId=3 where ID=1;--这就是事务,你们有见过只更新的一半儿的?"								
	begin tran--rollback/commit								
	默认开启事务,就是可以省略掉begin tran								
									
	ACID:								
	原子性	要么都成功  要么都失败							
	一致性	事务执行完,数据都是正确							
	隔离性	两个事务同时操作一张表,B事务要么是在A事务前完成,要么在A事务完成会执行(锁表)							
	持久性	数据提交后 就固化下来							
									
锁:	多用户同时访问一个数据资源								
	1	修改丢失							
	2	不可重复读							
	3	脏读/幻读							
	保证访问同一资源时,有个先后顺序管理,处理并发问题								
	乐观锁	认为没有并发,读取数据--更新--保存(没有锁)							
		更新的做一个判断-----时间戳/Version/检测更新字段/检查全部字段							
		"数据库增加一列TimeSpan,long;每次查询拿出来;更新时+1,;保存时判断是否大于数据库"							
		要保证任何操作都按照这个规范,所以也有个漏洞,其他渠道更新							
		性能高!!!							
									
	悲观锁	认为任何时候都可能多线程并发,读数据别人恰好在改							
		基于数据库锁的机制来完成							
		共享锁 S锁 读锁,允许别的事务来读,但是不允许修改;读完就释放,锁定数据页;(除非holdlock就一直锁定)							
		排他锁 X锁 写锁,准备写数据,不允许读也不允许写;							
		更新锁 U锁    先查询再更新,							
		行锁	where id=3						
		表锁	where 1=1						
									
	怎么避免死锁呢?(高并发下死锁是不可能避免,只能减少)								
	1	不用锁就不会死锁,乐观锁							
	2	统一操作顺序--先A后B再C							
	3	最小单元锁,锁里面操作尽量减少							
	4	避免事务中等待用户输入							
	5	减少数据库并发							
	6	分库分表表分区							
	7	降低事务级别							
	8	设置死锁时间  set lock_timeout(锁超时时间)							

存储过程	存储过程Procedure是一组为了完成特定功能的SQL语句集合,经编译后存储在数据库中,用户通过指定存储过程的名称并给出参数来执行。								
	存储过程不好维护;逻辑分散了;不好管理;全部数据库操作;								
	少用,大量复杂的逻辑、计算、数据传输,可以用,否则还是程序来完成								
									
触发器	触发器是一种特殊类型的存储过程,触发器主要是通过事件进行触发被自动调用执行的								
	不要用								
游标	游标实际上是一种能从多条数据记录的结果集中每次提取一条记录的机制								
	几乎不用								
视图	视图就是一个虚拟的数据表,该数据表中的数据记录是有一条查询语句的查询结果得到的   								
	没问题,有需要就用(多表拼成临时表,方便查询/权限控制)								
函数	不太推荐使用自定义函数,因为计算交给数据库,没法使用索引								
字段类型	看文档								
字段可空	数值类型的  不要可空,in查询  not in查询  会没有结果,,一般给个默认值								
	尽量非空,其他看情况(时间不适合默认值)								
统计字段	创建时间、创建人、最后更新时间、最后更新人、state、isEnable								 
软删除	假删除、逻辑删除,把状态改成删除,而不是物理删除				

数据库性能优化的三个方法

  1. 负载均衡:缺点,数据会延迟没法保证数据一致性,这种优化方式还是靠钱解决。
  2. 读写分离:一个主库多个从库,2-8原则。主要是发布订阅模式实现,数据量大的话主库还是扛不住。
  3. 数据库分库分表:主要有垂直和水平分割
    在这里插入图片描述

你可能感兴趣的:(数据库,数据库)