您好,欢迎来到99网。
搜索
您的当前位置:首页sqlserver函数大全

sqlserver函数大全

来源:99网
sqlserver函数⼤全

⼀旦成功地从表中检索出数据,就需要进⼀步操纵这些数据,以获得有⽤或有意义的结果。这些要求包括:执⾏计算与数算、转换数据、解析数值、组合值和聚合⼀个范围内的值等。

下表给出了T-SQL函数的类别和描述。函数类别聚合函数配置函数转换函数加密函数游标函数

⽇期和时间函数数学函数元数据函数排名函数⾏集函数安全函数字符串函数系统函数系统统计函数⽂本和图像函数

作⽤

执⾏的操作是将多个值合并为⼀个值。例如COUNT、SUM、MIN 和 MAX。

是⼀种标量函数,可返回有关配置设置的信息。将值从⼀种数据类型转换为另⼀种。

⽀持加密、解密、数字签名和数字签名验证。返回有关游标状态的信息。可以更改⽇期和时间的值。

执⾏三⾓、⼏何和其他数字运算。返回数据库和数据库对象的属性信息。

是⼀种⾮确定性函数,可以返回分区中每⼀⾏的排名值。返回可在 Transact-SQL 语句中表引⽤所在位置使⽤的⾏集。返回有关⽤户和⾓⾊的信息。

可更改 char、varchar、nchar、nvarchar、binary 和 varbinary的值。

对系统级的各种选项和对象进⾏操作或报告。返回有关 SQL Server 性能的信息。可更改 text 和 image 的值。

函数的组成

函数的⽬标是返回⼀个值。⼤多数函数都返回⼀个标量值(scalar value),标量值代表⼀个数据单元或⼀个简单值。实际上,函数可以返回任何数据类型,包括表、游标等可返回完整的多⾏结果集的类型。本章不准备讨论到这个深度,第12章将讲解如何创建和使⽤⽤户⾃定义函数,以返回更复杂的数据。

函数⼰经存在很长时间了,它的历史⽐SQL还要长。在⼏乎所有的编程语⾔中,函数调⽤的⽅式都是相同的:Result=Function()

在T-SQL中,⼀般⽤SELECT语句来返回值。如果需要从查询中返回⼀个值,就可以把SELECT当成输出运算符,⽽不⽤使⽤等号:SELECT Function()

⼀个论点

对于SQL函数⽽⾔,参数表⽰输⼊变量或者值的占位符。函数可以有任意个参数,有些参数是必须的,⽽有些参数是可选的。可选参数通常被置于以逗号隔开的参数表的末尾,以便于在函数调⽤中去除不需要的参数。

在SQL Server在线图书或者在线帮助系统中,函数的可选参数⽤⽅括号表⽰。在下列的CONVERT()函数例⼦中,数据类型的length和style参数是可选的:CONVERT (data-type [(length)], expression[,style])

可将它简化为如下形式,因为现在不讨论如何使⽤数据类型:CONVERT(date_type, expression[,style])

根据上⾯的定义,CONVERT()函数可接受2个或3个参数。因此,下列两个例⼦都是正确的:

SELECT CONVERT(Varchar(20), GETDATE())SELECT CONVERT(Varchar(20), GETDATE(), 101)

这个函数的第⼀个参数是数据类型Varchar(20),第2个参数是另⼀个函数GETDATE()。GETDATE()函数⽤datetime数据类型将返回当前的系统⽇期和时间。第2条语句中的第3个参数决定了⽇期的样式。这个例⼦中的101指以mm/dd/yyyy格式返回⽇期。本章后⾯将详细介绍GETDATE()函数。即使函数不带参数或者不需要参数,调⽤这个函数时也需要写上⼀对括号,例如GETDATE()函数。注意在书中使⽤函数名引⽤函数时,⼀定要包含括号,因为这是⼀种标准形式。

确定性函数

由于数据库引擎的内部⼯作机制,SQL Server必须根据所谓的确定性,将函数分成两个不同的组。这不是⼀种新时代的信仰,只和能否根据其输⼊参数或执⾏对函数输出结果进⾏预测有关。如果函数的输出只与输⼊参数的值相关,⽽与其他外部因素⽆关,这个函数就是确定性函数。如果函数的输出基于环境条件,或者产⽣随机或者依赖结果的算法,这个函数就是⾮确定性的。例如,GETDATE()函数是⾮确定性函数,因为它不会两次返回相同的值。为什么要把看起来简单的事弄得如此复杂呢?主要原因是⾮确定性函数与全局变量不能在⼀些数据库编程对象中使⽤(如⽤户⾃定义函数)。部分原因是SQL Server缓存与预编译可执⾏对象的⽅式。例如,即席查询可以使⽤任何函数,不过如果打算构建先进的、可重⽤的编程对象,理解这种区别很重要。

以下这些函数是确定性的:

l AVG()(所有的聚合函数都是确定性的)l CAST()l CONVERT()l DATEADD()l DATEDIFF()l ASCII()l CHAR()l SUBSTRING()

以下这些函数与变量是⾮确定性的:l GETDATE()l @@ERRORl @@SERVICENAME

l CURSORSTATUS()l RAND()

在函数中使⽤⽤户变量

变量既可⽤于输⼊,也可⽤于输出。在T-SQL中,⽤户变量以@符号开头,⽤于声明为特定的数据类型。可以使⽤SET或者SELECT语句给变量赋值。以下的例⼦⽤于将⼀个int类型的变量@MyNumber传递给SQRT()函数:

DECLARE @MyNumber intSET @MyNumber=144 SELECT SQRT(@MyNumber)

结果是12,即144的平⽅根。

⽤SET给变量赋值

以下例⼦使⽤另⼀个int型的变量@MyResult,来捕获该函数的返回值。这个技术类似于过程式编程语⾔中的函数调⽤样式,即把SET语句和⼀个表达式结合起来,给参数赋值:

DECLARE @MyNumber int, @MyResult intSET @MyNumber = 144

-- Assign the function result to the variable: SET @MyResult = SQRT(@MyNumber) -- Return the variable value SELECT @MyResult

⽤SELECT给变量赋值

使⽤SELECT的另⼀种形式也可以获得同样的结果。对变量要在赋值前要先声明。使⽤SELECT语句来替代SET命令的主要优点是,可以在⼀个操作内同时给多个变量赋值。执⾏下⾯的SELECT语句,通过SELECT语句赋值的变量就可以⽤于任何操作了。

DECLARE @MyNumber1 int, @MyNumber2 int,@MyResult1 int, @MyResult2 int

SELECT @MyNumber1 = 144, @MyNumber2 = 121 -- Assign the function result to the variable: SELECT @MyResult1 = SQRT(@MyNumber1),@MyResult2 = SQRT(@MyNumber2) -- Return the variable value

SELECT @MyResult1, @MyResult2

上⾯的例⼦⾸先声明了4个变量,然后⽤两个SELECT语句给这些变量赋值,⽽不是⽤4个SELECT语句给变量赋值。虽然这些技术在功能上是相同的,但是在服务器的资源耗费上,⽤⼀个SELECT语句给多个变量赋值⼀般⽐⽤多个SET命令的效率要⾼。将⼀个甚⾄多个值选进参数的是,对变量的赋值不能和数据检索操作同时进⾏。这就是上⾯的例⼦使⽤SELECT语句来填充变量,⽽⽤另外⼀个SELECT语句来检索变量中数据的原因。例如,下⾯的脚本就不能⼯作:

DECLARE @RestockName varchar(50) SELECT ProductId

,@RestockName = Name + ':' + ProductNumber FROM Production.Product

这个脚本会产⽣如下错误:消息141,级别15,状态1,第2 ⾏

向变量赋值的SELECT 语句不能与数据检索操作结合使⽤。

在查询中使⽤函数

函数经常和查询表达式结合使⽤来修改列值。这只需将列名作为参数传递给函数即可,随后函数将引⽤插⼊到SELECT查询的列的列表中,如下所⽰:

SELECT Title, NationalIDNumber, YEAR(BirthDate) AS BirthYear FROM HumanResources.Employee

在这个例⼦中,BirthDate列的值被作为参数传递给YEAR()函数。函数的结果是别名为BirthYear的列。

嵌套函数

我们需要的功能常常不能仅由⼀个函数来实现。根据设计,函数应尽量简单,⽤于提供特定的功能。如果⼀个函数要执⾏许多不同的操作,就变得复杂和难以使⽤。因此,每个函数通常仅执⾏⼀个操作,要实现所有的功能,可以将⼀个函数的返回值传递给另⼀个函数,这称为嵌套函数调⽤。

以下是⼀个简单的例⼦:GETDATE()函数的作⽤是返回当前的⽇期与时间,但不能返回经过格式化的数据,因为这是CONVERT()函数的功能。要想同时使⽤这两个函数,可以把GETDATE()函数的输出作为CONVERT()函数的输⼊参数。

SELECT CONVERT(Varchar(20), GETDATE(), 101)

聚合函数

报表的典型⽤途是从全部数据中提取出代表⼀种趋势的值或者汇总值,这就是聚合的意义。聚合函数回答数据使⽤者的如下问题:上个⽉鸡雏的总销售量是多少?

19~24岁之间的巴西男性在⾷品调味品上的平均⽀出是多少?上季度所有订单中从订购到运输的最长时间是多少?收发室⾥仍在⼯作的最⽼的员⼯是谁?

聚合函数应⽤特定的聚合操作并返回⼀个标量值(单⼀值)。返回的数据类型对应于该列或者传递到函数中的值。聚合经常和分组、累积以及透视等表运算⼀起使⽤,⽣成数据分析结果。第7章将详细介绍这个主题,这⾥仅讨论简单SELECT查询中的⼀些常⽤函数。

聚合函数不仅可⽤在SELECT查询中,还可以和标量输⼊值⼀起使⽤。那么,这样做的意义是什么呢?在下列代码中,将值15传递给下列聚合函数,每个函数的返回值都相同:

SELECT AVG(15)SELECT SUM(15)SELECT MIN(15)SELECT MAX(15)

它们都返回15。虽然,对同⼀个值求平均、求和、求最⼩值、求最⼤值,所得的结果还是那个值。如果对⼀个值计数,⼜会产⽣什么结果呢?

SELECT COUNT(15)

得到的值是1,因为函数只计数了⼀个值。

现在做⼀些有意义的事。聚合函数只有在处理结果集合中的⼀组数据时才有意义。每个函数都处理某列的⾮空值。除⾮使⽤分组操作(详见第7章),否则不能在同⼀个SELECT语句中既返回聚合的值,⼜返回常规的列值。

AVG()函数

AVG()函数⽤于返回⼀组数值中所有⾮空数值的平均值。例如,表6-2包含了体操成绩。表 6-2体操运动员SaraCassieDelaneySammiErikaSaraCassieDelaneySammiErika

对这些数据执⾏以下查询:SELECT AVG(Score)结果是8.965。

如果有三个⼥孩没有完成⼀些项⽬,在表中没有记录成绩,则可⽤NULL来表⽰(见表6-3)。表 6-3体操运动员SaraCassieDelaneySammiErikaSaraCassieDelaneySammiErika脚本:

create table #GymEvent(Player varchar(10),[Subject] nvarchar(5),Score decimal(4,2))go

insert into #GymEvent values('Sara','跳马',9.25)insert into #GymEvent values('Cassie','跳马',8.75)insert into #GymEvent values('Delaney','跳马',NULL)insert into #GymEvent values('Sammi','跳马',8.05)insert into #GymEvent values('Erika','跳马',8.60)insert into #GymEvent values('Sara','平衡⽊',9.70)insert into #GymEvent values('Cassie','平衡⽊',NULL)insert into #GymEvent values('Delaney','平衡⽊',9.25)insert into #GymEvent values('Sammi','平衡⽊',NULL)insert into #GymEvent values('Erika','平衡⽊',8.85)go

drop table #GymEvent

项 ⽬跳马跳马跳马跳马跳马平衡⽊平衡⽊平衡⽊平衡⽊平衡⽊成 绩9.258.759.258.058.609.709.009.258.958.85

项 ⽬跳马跳马跳马跳马跳马平衡⽊平衡⽊平衡⽊平衡⽊平衡⽊成 绩9.258.75NULL8.058.609.70NULL9.25NULL8.85

在这种情况下,计算平均值时只考虑实际的数值,NULL不参与运算,结果是8.921429。 但是,如果把缺少的成绩也算在内,即⽤数值0代替NULL,则会严重影响最终成绩(6.245),她们能不能进⼊国家级的⽐赛就难说了。

COUNT()函数

COUNT()函数⽤于返回⼀个列内所有⾮空值的个数,这是⼀个整型值。⽐如,在上⼀个例⼦中,体操数据被保存在#GymEvent表中,要确定Sammi参加的项⽬数,则可以执⾏下列查询:

SELECT COUNT(Score) FROM #GymEvent WHERE Player='Sammi'

结果是1,因为Sammi只参加了跳马⽐赛,她的平衡⽊成绩是NULL。

如果需要确定表中的⾏数,⽆论这些⾏是不是NULL值,都可以使⽤以下语法:

SELECT COUNT (*) FROM #GymEvent

以Sammi为例,COUNT(*)查询如下所⽰:

SELECT COUNT(*) FROM #GymEvent WHERE Player='Sammi'

由于COUNT(*)函数会忽略NULL值,所以这个查询的结果是2。

MIN()与MAX()函数

MIN()函数⽤于返回⼀个列范围内的最⼩⾮空值;MAX()函数⽤于返回最⼤值。这两个函数可以⽤于⼤多数的数据类型,返回的值根据对不同数据类型的排序规则⽽定。为了说明这两个函数,假设有⼀个表包含了两列值,⼀列是整型值,另⼀列是字符型值,如表6-4所⽰。

表 6-4

IntegerColumn(int类型)

241219脚本:

create table #Temp(IntegerColumn int,VarCharColumn varchar(10))go

insert into #Temp values(2,'2')insert into #Temp values(4,'4')insert into #Temp values(12,'12')insert into #Temp values(19,'19')go

drop table #Temp

VarCharColumn(varChar类型)

241219

如果分别调⽤MIN()与MAX()函数将会返回什么值呢?

select MIN(IntegerColumn),MAX(IntegerColumn) from #Tempselect MIN(VarCharColumn),MAX(VarCharColumn) from #Temp

因为VarCharColumn中值的存储类型为字符类型,⽽不是数字,所以结果以每个字符的ASCII值为顺序从左到右排序。这就是12⽐其他值⼩、⽽4⽐其他值⼤的原因。

SUM()函数

SUM()函数是最常⽤的聚合函数之⼀,它的功能很容易理解:和AVG()函数⼀样,它⽤于数值数据类型,返回⼀个列范围内所有⾮空值的总和。

配置变量

配置变量不是函数,不过它们的⽤法和系统函数相同。每个全局变量都能够返回SQL Server执⾏环境的标量信息。以下是⼀些常见的例⼦。

@@ERROR变量

这个变量包含当前连接发⽣的最后⼀次错误的代码。在执⾏的语句没有错误时,@@ERROR变量的值是0。出现标准错误时,错误是由数据库引擎引发的。所有的标准错误代码与消息都保存在sys.messages系统视图中,可以使⽤如下脚本查询:

SELECT * FROM sys.messages

定制错误可以通过调⽤RAISERROR语句来⼿动引发,并调⽤sp_addmessage系统存储过程将其添加到sysmessages表中。

以下是⼀个@@ERROR变量的简单例⼦。先试着将⼀个数除以0,数据库引擎会引发标准错误号为8134的错误。注意查看Results选项卡中的查询结果。在发⽣错误时,Management Studio的Messages选项卡将默认显⽰在Results选项卡的上⾯:

SELECT 5 / 0SELECT @@ERROR

在成功检索@@ERROR的值后,@@ERROR的值将返回0,因为@@ERROR只保存了上次执⾏的语句的错误代码。如果希望检索更多的错误信息,可以使⽤如下脚本从sysmessages视图中得到:

SELECT 5 / 0SELECT * FROM master.dbo.sysmessages WHERE error = @@ERROR

本节的后⾯部分内容将说明如何通过使⽤错误函数来更⾼效地返回错误数据。

除了美国英语之外,SQL Server还默认安装了其他语⾔。每种语⾔专⽤的错误消息都有⼀个语⾔标识符(mslangid),对应于syslanguages表中的⼀种语⾔,如下图所⽰。error81348134813481348134813481348134813481348134

1616161616161616161616

severity

00000000000

dlevel

description

Divide by zero error encountered.

Fehler aufgrund einer Division durch Null.Division par zéro.

0 除算エラーが発⽣しました。Error de división entre cero.Errore di divisione per zero.

Обнаружена ошибка: деление на ноль.Erro de divisão por zero.發現除以零的錯誤。0󰀀󰀀 󰀀󰀀󰀀 󰀀󰀀󰀀 󰀀󰀀󰀀󰀀󰀀󰀀.

遇到以零作除数错误。

10331031103610413082104010491046102810422052

msglangid

属性名mslangid被⾮正式地定义为Microsoft Global Language Identifier。微软公司⽤这个标识符来标识⼀种语⾔或语⾔和国家的组合,微软公司把语⾔和国家的组合定义为

地区。例如,在随SQL Server安装的英语中,美国英语的mslangid是1033,英国英语的mslangid是2057。要检索出所有已安装的、⽀持的语⾔,可以执⾏下⾯的查询:

SELECT alias, name, msglangidFROM sys.syslanguages

@@SERVICENAME变量

这个变量是⽤于执⾏和维护当前SQL Server实例的Windows服务名。它通常返回SQL Server默认实例MSSQLSERVER,但SQL Server的指定实例有唯⼀的服务名。例如在名为WoodVista的计算机上有两个SQL Server实例:默认实例和指定实例AughtEight。如在默认实例上检索@@SERVICENAME全局变量的内容,将返回MSSQLSERVER,但在指定实例上检索,会返回AUGHTEIGHT。

@@TOTAL_ERRORS变量

这个变量⽤于记录从打开当前连接开始发⽣的总错误次数。和@@ERROR变量⼀样,它对每个⽤户会话是唯⼀的,并将在连接关闭时被重置。

@@TOTAL_READ变量

这个变量记录从打开当前连接时开始计算的磁盘读取总数。DBA使⽤这个变量查看磁盘读取活动的情况。

@@VERSION变量

这个变量包含当前SQL Server实例的完整版本信息。

SELECT @@VERSION

⽐如,对于运⾏在Windows 7上的SQL Server 2008开发版实例,以上脚本能够返回如下信息:

Microsoft SQL Server 2008 (RTM) - 10.0.1600.22 (Intel X86) Jul 9 2008 14:43:34 Copyright (c) 1988-2008 Microsoft Corporation Enterprise Edition on Windows NT 6.1 (Build 7600: )

实际的版本号是⼀个简单的整型值,它在微软公司内部使⽤。⽽发⾏的产品可能有其他的商标名。在本例中,SQL Server 2005的版本是9,SQL Server 2008的版本是10。Windows XP Professional显⽰为Windows NT 5.l版,⽽Vista显⽰为6.0版。构建号⽤于内部控制,反映beta版和预览版以及正式发⾏后的补丁包的变化。

错误函数

前⾯学习了如何使⽤@@ERROR全局变量来检索错误信息。⽽返回所有错误数据的更好⽅法是使⽤错误函数。这些函数返回的信息可以存储在错误跟踪表中,以供错误审核。错误函数嵌套在错误处理例程中。第11章将详细讨论错误处理,其实通过使⽤嵌套在TRY和END TRY语句中的代码块,后跟⼀个放在CATCH和END CATCH语句中的代码块就可以实现错误处理。

--Try to do something BEGIN TRY SELECT 5 / 0 END TRY

--If it causes an error, do this BEGIN CATCH

PRINT ERROR_MESSAGE() END CATCH

所谓的错误捕获,其实就是这个意思。如果运⾏上⾯的⽰例,将不会出现可识别的错误,因为错误将被捕获并在CATCH语句块中进⾏处理。在编写错误处理代码时,SQL程序员必须把这些代码放在会引发系统错误的catch代码块中。

下列⼏个错误函数⽤于返回错误的特定信息:

函数

ERROR_MESSAGE()ERROR_NUMBER()ERROR_SEVERITY()ERROR_STATE()ERROR_LINE()

ERROR_PROCEDURE()

说明

返回错误的描述。返回错误号。

返回错误的严重级别。错误的严重级别是⼀个从0到25的整数。

返回错误的状态号。错误状态是⼀个整数,可以唯⼀地表⽰系统错误的原因。

返回例程中导致出错的⾏号。

返回发⽣错误的存储过程名或触发器名。

下表简要描述了严重级别。

严 重 级 别

0~1011~16171819202122232425

信息性消息。不会引发系统错误

⽤户可以更正的错误,例如违反了外键或主键规则⾮致命的、不重要的资源错误⾮致命的内部错误

致命的、不重要的资源错误当前进程中的致命错误

所有进程中的致命数据库错误致命的表完整性错误致命的数据库完整性错误致命的硬件错误致命的系统错误

说 明

下⾯脚本使⽤T-SQL的内置错误处理功能,来捕获和输出遇到除0错误时返回的错误数据。SELECT命令的结果将显⽰在Management Studio的消息选项卡中。

--Try to do something BEGIN TRY SELECT 5 / 0 END TRY

--If it causes an error, do this BEGIN CATCH

SELECT ERROR_MESSAGE(),ERROR_NUMBER(),ERROR_SEVERITY(), ERROR_STATE(),ERROR_LINE(),ERROR_PROCEDURE()END CATCH

可以看出,执⾏这个脚本会在消息选项卡中返回有关错误的更多详细信息,⽽不仅仅是错误号本⾝。ERROR_PROCEDURE()函数不能返回过程名,因为错误是在ad-hoc查询中⽣成的。

转换函数

数据类型转换可以通过CAST()和CONVERT()函数来实现。⼤多数情况下,这两个函数是重叠的,它们反映了SQL语⾔的演化历史。这两个函数的功能相似,不过它们的语法不同。虽然并⾮所有类型的值都能转变为其他数据类型,但总的来说,任何可以转换的值都可以⽤简单的函数实现转换。

CAST()函数

CAST()函数的参数是⼀个表达式,它包括⽤AS关键字分隔的源值和⽬标数据类型。以下例⼦⽤于将⽂本字符串'123'转换为整型:

SELECT CAST('123' AS int)

返回值是整型值123。如果试图将⼀个代表⼩数的字符串转换为整型值,⼜会出现什么情况呢?

SELECT CAST('123.4' AS int)

CAST()函数和CONVERT()函数都不能执⾏四舍五⼊或截断操作。由于123.4不能⽤int数据类型来表⽰,所以对这个函数调⽤将产⽣⼀个错误:Server: Msg 245, Level 16, State 1, Line 1 Syntax error converting the varchar value'123.4' to a column of data type int.

在将varchar 值'123.4' 转换成数据类型int 时失败。

要返回⼀个合法的数值,就必须使⽤能处理这个值的数据类型。对于这个例⼦,存在多个可⽤的数据类型。如果通过CAST()函数将这个值转换为decimal类型,需要⾸先定义decimal值的精度与⼩数位数。在本例中,精度与⼩数位数分别为9与2。精度是总的数字位数,包括⼩数点左边和右边位数的总和。⽽⼩数位数是⼩数点右边的位数。这表⽰本例能够⽀持的最⼤的整数值是9999999,⽽最⼩的⼩数是0.01。

SELECT CAST('123.4' AS decimal(9,2))

decimal数据类型在结果⽹格中将显⽰有效⼩数位:123.40

精度和⼩数位数的默认值分别是18与0。如果在decimal类型中不提供这两个值,SQL Server将截断数字的⼩数部分,⽽不会产⽣错误。

SELECT CAST('123.4' AS decimal)

结果是⼀个整数值:123

在表的数据中转换数据类型是很简单的。下⾯的例⼦使⽤Product表,⾸先执⾏如下查询:

SELECT ProductNumber, ProductLine, ProductModelIDFROM Production.Product

WHERE ProductSubcategoryID < 4

假定产品经理已经创建了⼀个系统,⽤于唯⼀地标识⽣产出来的每辆⾃⾏车,以便跟踪其型号、类型和类别。他决定合并产品号、产品⽣产线标识符、产品型号标识符和⼀个顺序号,为⽣产出来的每辆⾃⾏车创建⼀个唯⼀的序列号。在这个过程的第⼀步,他要求提供包括除顺序号之外的所有属性的所有可能产品的根标识符。

如果使⽤下⾯的表达式,就不能得到希望的结果,如图6-2所⽰。

SELECT ProductNumber + '-'

+ ProductLine + '-'

+ ProductModelID AS BikeSerialNumFROM Production.Product

WHERE ProductSubcategoryID < 4消息245,级别16,状态1,第1 ⾏

在将nvarchar 值'BK-R93R-62-R -' 转换成数据类型int 时失败。

我们没有得到希望的结果,⽽得到了有点奇怪的错误消息:请把nvarchar值转换为int。因为之前我们没有要求进⾏任何转换,所以这个错误很奇怪。这个查询的问题在于我们试图利⽤第⼀个连接符来连接字符值ProductNumber,利⽤第⼆个连接符连接另⼀个字符值ProductLine,最后连接的是ProductModelID字符值(它是⼀个整数)。

查询引擎会把连接符当成⼀个数算符,⽽不是⼀个字符。不管结果是什么,都需要更正这个表达式,以确保使⽤正确的数据类型。以下表达式执⾏了必要的类型转换,返回如图6-3所⽰的结果:

SELECT ProductNumber + '-'

+ ProductLine + '-'

+ CAST(ProductModelID AS char(4)) AS BikeSerialNum FROM Production.Product WHERE ProductSubcategoryID < 4

如果把整型值转换为字符类型就不会增加多余的空格了。查询引擎将把这些值⽤加号和连接符组合在⼀起,进⾏字符串连接运算,⽽不是和前⾯的数值进⾏加法或者减法运算了。

CONVERT()函数

对于简单类型转换,CONVERT()函数和CAST()函数的功能相同,只是语法不同。CAST()函数⼀般更容易使⽤,其功能也更简单。CONVERT()函数的优点是可以格式化⽇期和数值,它需要两个参数:第1个是⽬标数据类型,第2个是源数据。以下的两个例⼦和上⼀节的例⼦类似:

SELECT CONVERT(int, '123')

SELECT CONVERT(decimal(9,2), '123.4')

CONVERT()函数还具有⼀些改进的功能,它可以返回经过格式化的字符串值,且可以把⽇期值格式化成很多形式。有28种预定义的符合各种国际和特殊要求的⽇期与时间输出格式。下表列出了这些⽇期格式。

如果 expression 为 date 或 time 数据类型,则 style 可以为下表中显⽰的值之⼀。其他值作为 0 进⾏处理。SQL Server 使⽤科威特算法来⽀持阿拉伯样式的⽇期格式。yy(1)-12345678-101112-14------yyyy

0 或 100 (1, 2)101102103104105106 (1)107 (1)108

9 或 109 (1, 2)110111112

13 或 113 (1, 2)114

20 或 120 (2)21 或 121 (2)126 (4)127(6, 7)130 (1, 2)131 (2)

标准默认美国ANSI英国/法国德国意⼤利---默认设置 + 毫秒美国⽇本ISO

欧洲默认设置 + 毫秒-ODBC 规范

ODBC 规范(带毫秒)ISO8601

带时区 Z 的 ISO8601。回历 (5)回历 (5)

输⼊/输出 (3)

mon dd yyyy hh:miAM(或 PM)mm/dd/yyyyyy.mm.dddd/mm/yyyydd.mm.yydd-mm-yydd mon yymon dd, yyhh:mi:ss

mon dd yyyy hh:mi:ss:mmmAM(或 PM)mm-dd-yyyy/mm/ddyymmdd

yyyymmdd

dd mon yyyy hh:mi:ss:mmm(24h)hh:mi:ss:mmm(24h)

yyyy-mm-dd hh:mi:ss(24h)

yyyy-mm-dd hh:mi:ss.mmm(24h)

yyyy-mm-ddThh:mi:ss.mmm(⽆空格)yyyy-mm-ddThh:mi:ss.mmmZ(⽆空格)

dd mon yyyy hh:mi:ss:mmmAMdd/mm/yy hh:mi:ss:mmmAM

1. 这些样式值将返回不确定的结果。包括所有 (yy)(不带世纪数位)样式和⼀部分 (yyyy)(带世纪数位)样式。2. 默认值(style 0 或 100、9 或 109、13 或 113、20 或 120 以及 21 或 121)始终返回世纪数位 (yyyy)。3. 转换为 datetime 时输⼊;转换为字符数据时输出。

4. 为⽤于 XML ⽽设计。对于从 datetime 或 smalldatetime 到字符数据的转换,其输出格式如上⼀个表所述。5. 回历是有多种变体的⽇历系统。SQL Server 使⽤科威特算法。

a) 默认情况下,SQL Server 基于截⽌年份 2049 年来解释两位数的年份。换⾔之,就是将两位数的年份 49 解释为 2049,将两位数的年份 50 解释为 1950。许多客户

端应⽤程序(如基于⾃动化对象的应⽤程序)都使⽤截⽌年份 2030 年。SQL Server 提供了“两位数年份截⽌”配置选项,可通过此选项更改 SQL Server 使⽤的截⽌年份,从⽽对⽇期进⾏⼀致处理。建议您指定四位数年份。6. 仅⽀持从字符数据转换为 datetime 或 smalldatetime。仅表⽰⽇期或时间成分的字符数据转换为 datetime 或 smalldatetime 数据类型时,未指定的时间成分设置为

00:00:00.000,未指定的⽇期成分设置为 1900-01-01。7. 使⽤可选的时间区域指⽰符 (Z) 更便于将具有时区信息的 XML datetime 值映射到没有时区的 SQL Server datetime 值。Z 是时区 UTC-0 的指⽰符。其他时区则以 + 或 -⽅向的 HH:MM 偏移量来指⽰。例如:2006-12-12T23:45:12-08:00。从 smalldatetime 转换为字符数据时,包含秒或毫秒的样式将在这些位置上显⽰零。使⽤相应的 char 或 varchar 数据类型长度从 datetime 或 smalldatetime 值转换时,可截断不需要的⽇期部分。

从样式包含时间的字符数据转换为 datetimeoffset 时,将在结果末尾追加时区偏移量。

这个函数的第三个参数是可选的,该参数⽤于接收格式代码整型值。表中的例⼦⽤于对DateTime数据类型进⾏转换。在转换SmallDateTime数据类型时,格式不变,但⼀些元素会显⽰为0,因为该数据类型不⽀持毫秒。以下的脚本例⼦将输出格式化的⽇期:

SELECT 'Default Date:' + CONVERT(Varchar(50), GETDATE(), 100)

Default Date: Apr 25 2005 1:05PM

SELECT 'US Date:' + CONVERT(Varchar(50), GETDATE(), 101)

US Date: 04/25/2005

SELECT 'ANSI Date:' + CONVERT(Varchar(50), GETDATE(), 103)

ANSI Date: 2005.04.25

SELECT 'UK/French Date:' +CONVERT (Varchar(50), GETDATE(), 103)

UK/French Date: 25/04/2OO5

SELECT 'German Date:' + CONVERT(Varchar(50), GETDATE(), 104)

German Date: 25.04.2005

格式代码0,1和2也可⽤于数字类型,它们对⼩数与千位分隔符格式产⽣影响。⽽不同的数据类型所受的影响是不⼀样的。⼀般来说,使⽤格式代码0(或者不指定这个参数的值),将返回该数据类型最惯⽤的格式。使⽤1或者2通常显⽰更为详细或者更精确的值。以下例⼦使⽤格式代码0:

DECLARE @Num Money SET @Num = 1234.56

SELECT CONVERT(varchar(50), @Num, 0)

返回结果如下:1234.56

使⽤值1则返回如下结果:1,234.56

使⽤值2则返回如下结果:1234.5600

以下例⼦和上例相同,但是使⽤Float类型:

DECLARE @Num floatSET @Num = 1234.56

SELECT CONVERT(varchar(50), @Num, 2)

使⽤值0不会改变所提供的格式,但是使⽤值1或2将返回以科学计数法表⽰的数字,后者使⽤了15位⼩数:1.23456000000000e+003

STR()函数

这是⼀个将数字转换为字符串的快捷函数。这个函数有3个参数:数值、总长度和⼩数位数。如果数字的整数位数和⼩数位数(要加上⼩数点占⽤的⼀个字符)的总和⼩于总长度,对结果中左边的字符将⽤空格填充。在下⾯第1个例⼦中,包括⼩数点在内⼀共是5个字符。结果显⽰在⽹格中,显然左边的空格被填充了。这个调⽤指定,总长度为8个字符,⼩数位为4位:

SELECT STR(123.4, 8, 4)

结果值的右边以0填充:123.4000。

下⾯给函数传递了⼀个10字符的值,并指定结果包含8个字符,有4个⼩数位:

SELECT STR(123.4567, 8, 4)

只有将这个结果截断才能符合要求。STR()函数对最后⼀位进⾏四舍五⼊:123.4568。现在,如果为函数传递数字1,并指定结果包含6个字符,有4个⼩数位,STR()函数将⽤0补⾜右边的空位:

SELECT STR(1, 6, 4)

1.0000

然⽽,如果指定的总长度⼤于整数位数、⼩数点和⼩数位数之和,结果值的左边将⽤空格补齐:

SELECT STR(1, 6, 4)

1.0000

SELECT STR(1, 12, 4)

---------- 1.0000

游标函数与变量

游标可以处理多⾏数据,在过程循环中⼀次访问⼀⾏。和基于集合的⾼效操作相⽐,这个功能对系统资源的消耗更⼤。可以⽤⼀个函数和两个全局变量来管理游标操作。

CURSOR_STATUS()函数

这个函数返回⼀个整型值,表⽰传递给这个函数的游标类型变量的状态。有很多不同类型的游标会影响这个函数的操作。为简单起见,下表列出了这个函数的常见返回值。返 回 值10-1-2-3

说 明

游标包含⼀⾏或多⾏(动态游标包含0⾏或者多⾏)游标不包含⾏游标已关闭游标未分配游标不存在

@@CURSOR_ROWS全局变量

这个变量是⼀个整型值,表⽰在当前连接中打开的游标中的⾏数。根据游标类型,这个值也能不代表结果集中的实际⾏数。

@@FETCH_STATUS全局变量

这个变量是⼀个标记,⽤于表⽰当前游标指针的状态。这个变量主要⽤来判断某⾏是否存在,以及在执⾏了FETCH NEXT语句后,是否已执⾏到结果集的尾部。打开游标时,@@FETCH_STATUS变量值为-1。⼀旦把第⼀个值放在游标中,@@FETCH_STATUS变量值就变成0。当不再把更多的⾏放在游标中时,该变量的值将变回-1。

⽇期函数

这些函数可以操作DateTime与SmallDateTime类型的值。有些函数可⽤于解析⽇期值的⽇期与时间部分,有些函数可⽤于⽐较、操纵⽇期/时间值。⽇期数据类型的区别如下表所⽰。数据类型timedate

smalldatetimedatetimedatetime2

输出

12:35:29. 12345672007-05-08

2007-05-08 12:35:00

2007-05-08 12:35:29.123

2007-05-08 12:35:29. 1234567

datetime2datetimeoffset

2007-05-08 12:35:29. 1234567

2007-05-08 12:35:29.1234567 +12:15

DATEADD()函数

DATEADD()函数⽤于在⽇期/时间值上加上⽇期单位间隔。⽐如,要得到2007年4⽉29⽇起90天后的⽇期,可以使⽤下列语句:

SELECT DATEADD(DAY, 90, '4-29-2007')

结果:2007-07-28 00:00:00.000

可以把下表的值作为时间间隔参数传递给DATEADD()函数。

datepart

yearquartermonthdayofyeardayweekweekdayhourminutesecondmillisecondmicrosecondnanosecond

在下⾯列出的例⼦中,我们使⽤和上⼀个例⼦⼀样的⽇期,并且在这些例⼦中还包含了时间数据。每个操作的结果将显⽰在查询的下⼀⾏中。18年后:

SELECT DATEADD(YEAR, 18, '4-29-1988 10:30 AM')

缩写

yy, yyyyqq, qmm, mdy, ydd, dwk, wwdw, whhmi, nss, smsmcsns

2006-04-29 10:30:00.00018年前:

SELECT DATEADD(YY, -18, '4-29-1988 10:30 AM')

1970-04-29 10:30:00.0009000秒后:

SELECT DATEADD(SECOND, 9000, '4-29-1988 10:30 AM')

1988-04-29 13:00:00.0009000000毫秒前:

SELECT DATEADD(MS, -9000000, '4-29-1988 10:30 AM')

1988-04-29 08:00:00.000

可以将CONVERT()函数和DATEADD()函数组合在⼀起,来对19年9⽉8⽇9个⽉前的⽇期值进⾏格式化。

SELECT CONVERT(varchar(20), DATEADD(M, -9, '9-8-19'), 101)

12/08/1988

这将返回⼀个可变长度的字符值,⽐前⾯例⼦结果中的默认⽇期更易容易理解。这是⼀个函数嵌套调⽤,DATEADD()函数的返回值(⼀个DateTime类型的值)被作为值参数传递给CONVERT()函数。

DATEDIFF()函数

DATEADD()和DATEDIFF()函数可以看作⼀对表兄弟,有点像乘法与除法。在等式的两端有4个元素:起始⽇期、时间间隔(datepart)、差值和最终⽇期。如果已知其中的三个值,就可以求出第4个值。如果在DATEADD()函数中使⽤起始⽇期、⼀个整型值和⼀个时间间隔,就可返回与起始⽇期相关的最终⽇期值。如果提供了起始⽇期、时间间隔和最终⽇期,DATEDIFF()函数就可以返回差值。

为了说明这⼀点,我们选择任意两个⽇期与⼀个时间间隔作为参数。这个函数将以所提供的时间间隔为单位返回两个⽇期之间的差值。要知道19年9⽉8⽇和1991年10⽉17⽇之间差了⼏个⽉,可编写如下查询代码:

SELECT DATEDIFF(MONTH, '9-8-19', '10-17-1991')

结果是25个⽉。如果以⽇期为单位呢?

SELECT DATEDIFF(DAY, '9-8-19', '10-17-1991')

结果是769天。

1996年7⽉2⽇和1997年8⽉4⽇之间差⼏个星期?

SELECT DATEDIFF(WEEK, '7-2-1996', '8-4-1997')

57星期。甚⾄可以算出⾃⼰的年龄是多少秒:

DECLARE @MyBirthDate datetime SET @MyBirthDate = '7-16-1962'

SELECT DATEDIFF(SS, @MyBirthDate, GETDATE())

结果显⽰有些⼈已经活了15亿秒了!

可以将列名作为参数,把这个函数⽤在查询中。⾸先建⽴⼀个简单的表,其中包含⼀些⼈的姓名和⽣⽇:

SELECT c.FirstName ,c.LastName ,e.BirthDate

,DATEDIFF(YEAR, e.BirthDate, GETDATE()) AS ApproximateAgeFROM HumanResources.Employee as e inner join Person.Contact as c on e.ContactID = c.ContactIDorder by c.LastName

下图显⽰了结果:

初看起来结果是对的,但存在的问题是年龄值没有精确到⽇。⽐如,根据表中的数据,Nancy的⽣⽇是12⽉21⽇,他今年将庆祝第32个⽣⽇(这个查询在2010年8⽉运⾏)。如果依据上述计算结果来确定他的年龄何时变化,就应在⼀⽉份的某天给他发⽣⽇卡⽚,这⽐实际⽇期提前了11个⽉。

除⾮⽤更⼩的时间单位来计算这些⽇期的差,否则结果只在雇员实际⽣⽇的⼀年以内是精确的。以下例⼦将⽤差值除以⼀年(包括闰年)的天数,并将结果值转换为int类型,进⾏取整运算,⽽不是四舍五⼊。

SELECT c.FirstName ,c.LastName ,e.BirthDate

,DATEDIFF(YEAR, e.BirthDate, GETDATE()) AS ApproximateAge ,CONVERT(int, DATEDIFF(DAY, e.BirthDate, GETDATE())/365) AS AgeFROM HumanResources.Employee as e inner join Person.Contact as c on e.ContactID = c.ContactIDorder by c.LastName

⽐较这次的结果和上⼀个例⼦的结果,看看有什么不同。

可以看到,Nancy是31岁,其他雇员的年龄也精确到了天。表中的BirthDate列存储雇员的⽣⽇,并以午夜(00:00:00AM)为界,这是⼀天中的第⼀秒。GETDATE()函数返回当前的时间与⽇期。当前两个⽇期相差约8⼩时(写这段⽂字时是上午8点)。如果希望这个计算更精确,就需要在当前⽇期的午夜把GETDATE()函数的结果转换为datetime类型。

DATEPART()与DATENAME()函数

这两个函数⽤于返回datetime或者shortdatetime值的⽇期部分。DATEPART()函数返回⼀个整型值;DATENAME()函数返回⼀个包含描述性⽂字的字符串。⽐如,将⽇期4-29-1988传递给DATEPART()函数,如指定返回⽉份值,则返回数字4:

SELECT DATEPART(MONTH, '4-29-1988')

⽽使⽤相同的参数,DATENAME()函数返回04(这取决于你的机器的本地语⾔,如果是英⽂版,那么将返回April): SELECT DATENAME(MONTH, '4-29-1988')

这两个函数都接收和DATEADD()函数⼀样的时间间隔参数常量。

GETDATE()与GETUTCDATE()函数

这两个函数都⽤于返回datetime类型的当前⽇期与时间。GETUTCDATE()函数使⽤服务器上的时区设置来求出UTC时间,这和格林威治标准时间或飞⾏员所说的\"祖鲁时\"(Zulu Time)是⼀样的。两个函数都能精确到3.33毫秒。

SELECT GETDATE() SELECT GETUTCDATE()

执⾏这两个函数,都将返回未经格式化的结果,见下图:

我在北京,和UTC时间相差8个⼩时,和标准时间相差9个⼩时。可以使⽤如下DATEDIFF()函数来验证这个时间差值: SELECT DATEDIFF(HOUR, GETDATE(), GETUTCDATE())

SYSDATETIME()和SYSUTCDATETIME()函数

这两个SQL Server 2008函数等价于GETDATE()和GETUTCDATE()函数,但不是返回datetime数据类型的结果,⽽是返回SQL Server 2008新的datetime2数据类型的结果,该数据类型可以精确到100纳秒,当然这取决于服务器安装的硬件。

SELECT SYSDATETIME() SELECT SYSUTCDATETIME()

DAY()、MONTH()和YEAR()函数

这三个函数分别返回以整数表⽰的datetime或者smalldatetime类型值的⽇、⽉、年。它们的⽤途很⼴泛,如可以创建独特的个性化⽇期格式。假设需要创建⼀个⾃定义的⽇期值作为字符串,通过将这三个函数的输出结果转换成字符类型,然后进⾏连接操作,就可以对输出结果以任何形式进⾏组合了:

SELECT 'Year: ' + CONVERT(varchar(4), YEAR(GETDATE())) + ', Month: ' + CONVERT(varchar(2), MONTH(GETDATE())) + ', Day: ' + CONVERT(varchar(2), DAY(GETDATE()))

这个脚本⽣成下列结果:Year:2008, Month:2, Day:20

下⼀节将讨论字符串操纵函数,并使⽤相似的技术来构建⼀个紧凑的定制时间戳。

字符串操纵函数

字符串函数可以解析、替换、操纵字符型值。在处理原始字符数据时,最⼤的挑战之⼀是如何可靠地提取出有意义的信息。有很多字符串解析函数可⽤于标识和解析⼦字符串(⼀个⼤字符型值的⼀部分)。我们⼀直在做这种事,在我们阅读⽂件、或者书⾯材料时,就会本能地标识、分离出有意义的信息⽚段。这个过程的⾃动化⾮常困难,即使是处理不太复杂的⽂本,也很困难。这些函数包含⼏乎所有必需的⼯具,⽽挑战在于如何找出最简单、最⾼效的⽅法。

ASCII()、CHAR()、UNICODE()和NCHAR()函数

这四个函数是相似的,它们都可以在字符和字符的标准数字表⽰之间转换。美国标准信息交换码(American Standard Code for Information Interchange,ASCII)标准字符集包含128个字母、数字和标点符号。这个字符集是IBM PC体系结构的基础,虽然有些字符现在看来已经很古⽼了,但还是被保留了下来,且仍是现代计算机技术的核⼼。如果在计算机上使⽤英语,则键盘上的每个字符都是⽤ASCII码表⽰的。这对说英语(⾄少以英语打字)的计算机⽤户来说是有利的,但是其他⼈⼜该怎么办呢?

在计算机的发展过程中, ASCII字符集发布没多长时间便过时了。⼈们很快将它扩展成为256个字符的ANSI字符集,⼀个字符⽤⼀个字节来保存。这个扩展的字符列表满⾜了许多其他⽤户的需求,可以⽀持主要的欧洲语⾔字符,不过仍是美国标准(由美国国家标准学会持有),仍建⽴在最初的英语字符集的基础上。为了⽀持所有可印刷的语⾔,⼈们制订了Unicode标准,它⽀持多种语⾔特定的字符集。每个Unicode字符需要2个字节的存储空间,是ASCII与ANSI字符的两倍。但是使⽤2个字就可以表⽰超过65 000个不同的字符,完全能够⽀持东欧和亚洲字符。SQL Server同时⽀持ASCII与Unicode两种标准。

ASCII()和CHAR()是两个基于ASCII的函数,这两个函数可将计算机上应⽤的每个字符表⽰为数字。要确定代表⼀个字符的数字是什么,就应给ASCII()函数传送只包含⼀个字符的字符串,如下:

SELECT ASCII('A')

结果是65。

如要将⼀个已知数字转换为字符,⼜该怎么办?使⽤CHAR()函数即可:

SELECT CHAR(65)

结果是字母A。

要得到完整的ASCII字符值列表,可以对⼀个临时表填充从0到127的数字,然后调⽤CHAR()函数返回相应的字符。为了节省空间,我们对以下这个脚本进⾏了删节,但包含整个结果集,并以多栏格式给出。

-- 创建⼀个临时表来保存ASCII码:

Create Table #ASCIIVals (ASCIIValue smallint) -- 插⼊数字0 - 127 到临时表中:declare @Number intset @Number = 0while(@Number < 128) begin

Insert Into #ASCIIVals (ASCIIValue) Select @Number set @Number = @Number + 1 end

-- 查询所有的整型数字与其对应的ASCII码:

SELECT ASCIIValue, CHAR(ASCIIValue) AS Character FROM #ASCIIValsdrop table #ASCIIVals

表6-12是以多栏⽹格重新格式化的结果集。需要注意的是这⾥将不可印刷的控制字符以⽅括号表⽰。由于许多因素,如所安装的字体或语⾔不同,下表的显⽰可能会有稍许差异。

UNICODE()函数是ASCII()的Unicode等价函数,NCHAR()函数和CHAR()函数的功能相同,只不过NCHAR()是⽤于Unicode字符的。SQL Server的nchar与nvarchar类型能存储任何Unicode字符,可以和这两个函数⼀起使⽤。对于特别⼤的值,ntext类型和nvarchar(max)类型也⽀持Unicode字符。

要返回扩展字符编码集中的字符,可以将字符编码传递给NCHAR()函数:

SELECT NCHAR(220)

返回字母ü。

SELECT NCHAR(233)

返回带重⾳符号的⼩写e:é。

SELECT NCHAR(241)

返回西班⽛语的\"enya\",或者带有发⾳符号的n:。

当然,ASCII标准也⽀持所有的欧洲字符,所以使⽤CHAR()函数也可以返回这些扩展字符。如果对256~65536之间的值使⽤CHAR()函数,返回值就很有趣了。例如,下⾯的查询返回希腊字符Ω:

SELECT NCHAR(433)

下⾯的查询返回西⾥尔字母Ya(Я)。

SELECT NCHAR(1071)

CHARINDEX()和PATINDEX()函数

CHARINDEX()是原始的SQL函数,⽤于寻找在⼀个字符串中某⼦字符串第⼀次出现的位置。如函数名所⽰,这个函数返回⼀个整型值,表⽰某⼦字符串的第⼀个字符在整个字符串中的位置索引。以下脚本⽤于在字符串Washington中寻找⼦字符串sh的出现位置:

SELECT CHARINDEX('sh', 'Washington')

返回的结果是3,表明s是字符串Washington中的第3个字符。这说明CHARINDEX函数匹配字符的索引是从1开始的。如果没有匹配到任何结果,函数将返回0。在这个例⼦中使⽤两个字符作为⼦字符串并没有特别意义,但是如果字符串包含多个s字符,就有意义了。

PATINDEX()函数和CHARINDEXO函数类似,它执⾏相同的操作,但⽅法稍许不同,该函数增加了对通配符(即Like运算符中使⽤的字符)的⽀持。顾名思义,它将返回⼀个字符模式的索引。这个函数也可以和ntext、nchar(max)和nvarchar(max)等⼤字符类型⼀起使⽤。注意,如果和这些⼤字符类型⼀起使⽤,PATINDEX()函数将返回bigint类型的值,⽽不是int类型的值。以下是⼀个例⼦:

SELECT PATINDEX('%M_rs%', 'The stars near Mars are far from ours')

注意,如果想找到⼀个字符串,在所⽐较的字符串的前后各有0个或者多个字符,则两个百分符都是必须的。下划线表明这个位置上的字符不必匹配,它可以是任意字符。和使⽤相同字符串的CHARINDEX()函数作⼀下⽐较:

SELECT CHARINDEX('Mars', 'The stars near Mars are far from ours')

这两个函数都返回索引值16。请注意这些函数的执⾏过程。下⼀节将把这两个函数和SUBSTRING()函数组合在⼀起,演⽰如何使⽤界定符解析字符串。

LEN()函数

LEN()函数⽤于返回⼀个代表字符串长度的整型值。这是⼀个简单、有⽤的函数,经常与其他函数⼀起使⽤,来应⽤业务规则。以下例⼦将⽉份和⽇期转换为字符类型,然后测试它们的长度。如果⽉份⽇期只有⼀个字符,就填充字符0,然后组合成⼀个8字符的美国格式的⽇期字符串(MMDDYYYY)。

DECLARE @MonthChar varchar(2), @DayChar varchar(2), @DateOut char(8) SET @MonthChar = CAST(MONTH(GETDATE()) AS varchar(2)) SET @DayChar = CAST(DAY(GETDATE()) AS varchar(2)) -- Make sure month and day are two char long: IF LEN(@MonthChar) = 1

SET @MonthChar = '0' + @MonthChar IF LEN(@DayChar) = 1

SET @DayChar = '0' + @DayChar -- Build date string:

SET @DateOut = @MonthChar + @DayChar + CAST(YEAR(GETDATE()) AS char(4)) SELECT @DateOut AS OutputDate

这个脚本将返回代表⽇期的8个字符:08152010

LEFT()和RIGHT()函数

LEFT()与RIGHT()函数是相似的,它们都返回⼀定长度的⼦字符串。这两个函数的区别是,它们返回的分别是字符串的不同部分。LEFT()函数返回字符串最左边的字符,顺序从左数到右。RIGHT()函数正好相反,它从最右边的字符开始,以从右到左的顺序返回特定数量的字符。看⼀看使⽤这两个函数返回\"GeorgeWashington\"这个字符串的⼦字符串的例⼦。

如果使⽤LEFT()函数返回⼀个5字符的⼦字符串,则函数先定位最左边的字符,向右数5个字符,然后返回这个⼦字符串,如下所⽰。

DECLARE @FullName varchar(25) SET @FullName = 'George Washington'SELECT LEFT(@FullName, 5)

结果为:Georg

如果使⽤RIGHT()函数返回⼀个5字符的⼦字符串,则函数先定位最右边的字符,向左数5个字符,然后返回这个⼦字符串,如下所⽰。

DECLARE @FullName varchar(25) SET @FullName = 'George Washington'SELECT RIGHT (@FullName, 5)

结果为:ngton

要想返回字符串中有意义的部分,这两个函数都不是特别有⽤。如果想返回全名中的姓⽒或者名字,该怎么办?这需要多做⼀点⼯作。如果能确定每个姓名中空格的位置,就可以使⽤LEFT()函数在全名中读取名字。在这种情况下,可以使⽤CHARINDEX()或者PATINDEX()函数来定位空格,然后使⽤LEFT()函数返回空格前的字符。下⾯是第⼀个⽤过程⽅法编写的例⼦,它将处理过程分解成以下步骤:

DECLARE @FullName varchar(25), @SpaceIndex tinyint SET @FullName = 'George Washington'-- Get index of the delimiting space:

SET @SpaceIndex = CHARINDEX(' ' , @FullName) -- Return all characters to the left of the space: SELECT LEFT(@FullName, @SpaceIndex - 1)

结果为:George

如果不想在结果中包含空格,就需要从@SpaceIndex值中减去1,这样结果中就只有名字了。

SUBSTRING()函数

SUBSTRING()函数能够从字符串的⼀个位置开始,往右数若⼲字符,返回⼀个特定长度的⼦字符串。和LEFT()函数不同之处是,该函数可以指定从哪个位置开始计数,这样就可以在字符串的任何位置摘取⼦字符串了。这个函数需要三个参数:要解析的字符串、起始位置索引、要返回的⼦字符串长度。如果要返回到所输⼊字符串尾部的所有字符,可以使⽤⽐所需长度更⼤的长度值。SUBSTRING()函数将返回最⼤可能长度的字符数,⽽不会将多出的长度以空格填充。

只要指定字符串最左边的字符(1)为起始索引,就可以⽤SUBSTRING()函数替代LEFT()函数。

继续上⼀节的例⼦。可以设置起始位置与长度,返回姓名字符串中间的值。在这个例⼦中,从位置4开始,返回⼀个6字符的⼦字符串\"rge Wa\"。

DECLARE @FullName varchar(25) SET @FullName = 'George Washington'SELECT SUBSTRING(@FullName, 4, 6)

现在将上述各函数组合在⼀起,即可从名字+空格+姓⽒格式的全名字符串中解析出名字和姓⽒。使⽤先前的逻辑,通过函数嵌套来减少脚本的⾏数,并去掉@SpaceIndex变量。下⾯⽤SUBSTRING()函数替代LEFT()函数:

DECLARE @FullName varchar(25) SET @FullName = 'George Washington'-- Return first name:

SELECT SUBSTRING(@FullName, 1, CHARINDEX(' ', @FullName) - 1)

类似的逻辑可以⽤于解析姓⽒,但是必须将起始位置更改为空格后的那个字符。如果空格在第7个位置上,那么姓⽒将从第8个位置开始。这就意味着起始位置是CHARINDEX()的返回结果加上1。

DECLARE @FullName varchar(25) SET @FullName = 'George Washington'--Return last name:

SELECT SUBSTRING(@FullName, CHARINDEX(' ', @FullName) + 1,LEN(@FullName))

把上述步骤组合在⼀起,就可以运⾏下⾯的查询,从全名变量中提取出名字和姓⽒:

DECLARE @FullName varchar(25)SET @FullName = 'George Washington'-- Return first name:

SELECT SUBSTRING(@FullName, 1, CHARINDEX(' ',@FullName) - 1) AS FirstName, SUBSTRING(@FullName, CHARINDEX(' ',@FullName) + 1, LEN(@FullName)) AS LastName

结果为:

传递给SUBSTRING()函数的值是空格所在位置加上1,并将该值作为起始位置,这将是姓⽒的第1个字母。由于不可能总是知道名字的长度,所以将LEN()函数的结果作为⼦字符串长度参数传递进来,当SUBSTRING()函数到达这个位置时,就到达了字符串的末尾,这样就可以将字符串中从空格后⾯开始的所有字符都包含进来了。

为了举例⽅便,先创建并填充⼀个临时表:

CREATE TABLE #MyNames (FullName varchar(50)) GO

INSERT INTO #MyNames (FullName) SELECT 'Fred Flintstone'INSERT INTO #MyNames (FullName) SELECT 'Wilma Flintstone'INSERT INTO #MyNames (FullName) SELECT 'Barney Rubble'INSERT INTO #MyNames (FullName) SELECT 'Betty Rubble'INSERT INTO #MyNames (FullName) SELECT 'George Jetson'INSERT INTO #MyNames (FullName) SELECT 'Jane Jetson'go

--drop table #MyNames

下⾯执⾏⼀个使⽤函数调⽤来解析名字和姓⽒值的单⾏查询表达式。这⾥对@FullName变量的引⽤被表中的FullName列所替代:

SELECT

SUBSTRING(FullName, 1, CHARINDEX(' ', FullName) - 1) AS FirstName

,SUBSTRING(FullName, CHARINDEX(' ', FullName) + 1, LEN(FullName)) AS LastNameFROM #MyNames

在下图所⽰的结果中,显⽰了两个不同的列,分别是名字和姓⽒。

LOWER()和UPPER()函数

这两个函数很容易理解,它们⽤于将字符串中所有字符分别都转换为⼩写和⼤写,这在⽐较⽤户输⼊或者存储⽤于⽐较的字符串时是⾮常有⽤的。字符串⽐较通常是区分⼤⼩写的,这取决于SQL Server安装时的设置。如果和其他的字符串操纵函数⼀起使⽤,就可以将字符串转换为合适的⼤⼩写,以便存储或显⽰。以下例⼦说明混合⼤⼩写的名字,假设名字中的第2个⼤写⼦字符串前只包含⼀个空格,但在特殊情况下也有⼀些名字是没有空格的。这个例⼦很容易通过扩展来处理包含其他类型的混合⼤⼩写名字(如以MC开头的名字,带连接号的名字等)。

DECLARE @LastName varchar(25), @SpaceIndex tinyint SET @LastName = 'mc donald' -- Test value -- Find space in name:

SET @SpaceIndex = CHARINDEX(' ' , @LastName)

IF @SpaceIndex > 0 -- Space: Capitalize first & substring SELECT UPPER(LEFT(@LastName, 1))

+ LOWER(SUBSTRING(@LastName, 2, @SpaceIndex - 1)) + UPPER(SUBSTRING(@LastName, @SpaceIndex + 1, 1))

+ LOWER(SUBSTRING(@LastName, @SpaceIndex + 2, LEN(@LastName))) ELSE -- No space: Cap only first char. SELECT UPPER(LEFT(@LastName, 1))

+ LOWER(SUBSTRING(@LastName, 2, LEN(@LastName)))

这个脚本将返回MC Donald。还可以对这个例⼦进⾏扩展,以处理姓⽒包含撇号的情况。在这个例⼦的业务规则中,空格是不考虑的。如果找到了撇号,就将后⾯的字符全部转为⼤写。请注意如果要在脚本中测试撇号,就必须输⼊两次撇号(' '),以表明这是⼀个⽂字,⽽不是⼀对单引号。姓⽒中只存储⼀个撇号。

DECLARE @LastName varchar(25), @SpaceIndex tinyint, @AposIndex tinyint DECLARE @LastName varchar(25), @SpaceIndex tinyint, @AposIndex tinyint SET @LastName = 'o''malley' -- Test value -- Find space in name:

SET @SpaceIndex = CHARINDEX(' ', @LastName) -- Find literal ' in name:

SET @AposIndex = CHARINDEX('''', @LastName)

IF @SpaceIndex > 0 -- Space: Capitalize first & substring SELECT UPPER(LEFT(@LastName, 1))

+ LOWER(SUBSTRING(@LastName, 2, @SpaceIndex - 1)) + UPPER(SUBSTRING(@LastName, @SpaceIndex + 1, 1))

+ LOWER(SUBSTRING(@LastName, @SpaceIndex + 2, LEN(@LastName))) ELSE IF @AposIndex > 0 -- Apostrophe: Cap first & substring SELECT UPPER(LEFT(@LastName, 1))

+ LOWER(SUBSTRING(@LastName, 2, @AposIndex - 1)) + UPPER(SUBSTRING(@LastName, @AposIndex + 1, 1))

+ LOWER(SUBSTRING(@LastName, @AposIndex + 2, LEN(@LastName))) ELSE -- Nospace: Cap only first char. SELECT UPPER(LEFT(@LastName, 1))

+ LOWER(SUBSTRING(@LastName, 2, LEN(@LastName)))

这个脚本返回O'Malley。

LTRIM()和RTRIM()函数

这两个函数分别返回将字符串的左边和右边的空⽩修剪掉之后的字符串:

DECLARE @Value1 char(10), @Value2 char(10) SET @Value1 = 'One'SET @Value2 = 'Two'

SELECT @Value1 + @Value2

SELECT CONVERT(varchar(5), LEN(@Value1 + @Value2))+ ' characters long. '

SELECT RTRIM(@Value1) + RTRIM(@Value2)

SELECT CONVERT(varchar(5), LEN(RTRIM(@Value1) + RTRIM(@Value2))) + ' characters long trimmed. '

结果如下:

REPLACE()函数

REPLACE()函数可以把字符串中的某个字符或某个⼦字符串替换为另⼀个字符或者⼦字符串,该函数可以⽤于全局查找和替换⼯具中。

DECLARE @Phrase varchar(1000) SET @Phrase = 'I aint gunna use poorgrammar when commenting script and I aint gunna complain about it. '

SELECT REPLACE(@Phrase, 'aint', 'am not')

REPLICATE()和SPACE()函数

在需要将⼀些字符重复填充进⼀个字符串时,这两个函数是⾮常有⽤的。这⾥也使⽤SUBSTRING()例⼦中的临时表为每个名字填满20个字符,然后将20减去各个字符串的长度,以便将正确的值传递给REPLICATE()函数:

SELECT FullName + REPLICATE('*', 20 - LEN(FullName))FROM #MyNames

结果是每个名字后⾯都填满了星号,各个名字的总长度都是20个字符:Fred Flintstorle***** Wilrna Flintstone**** Barney Rubble******* Betty Rubble******** George Jetson******** Jane Jetson**********

SPACE()函数与上述函数类似,区别在于该函数使⽤空格进⾏填充。它返回⼀个由空格组成的字符串,空格的个数由参数定义。

SELECT FullName + SPACE(20 - LEN(FullName)) FROM #MyNames

如果返回\"#MyNames表不存在\"的错误,只需再次运⾏本⽂前⾯\"SUBSTRING()函数\"⼀节的CREATE TABLE脚本即可。

REVERSE()函数

顾名思义,这个函数⽤于将字符串中的字符颠倒过来。这在处理连接列表中的单个字符值时将会被⽤到。

SELECT REVERSE('The stars near Mars are far from ours. ')

结果为:.sruo morf raf era sraM raen srats ehT

STUFF()函数

这个函数可将字符串中的⼀部分替换为另⼀个字符串。它本质上是将⼀个字符串以特定的长度插⼊另⼀个字符串中的特定位置上。这对于源值与⽬的值的长度不⼀样的字符串替换是很有⽤的。下列代码⽤于将字符串中的价格替换为109.95:

Please submit your payment for 99.95 immediately.

价格值是从第32个字符开始的,有5个字符长。在这个位置上插⼊的⼦字符串有多长并不重要,只需要知道需要删除多少个字符就可以了。 SELECT STUFF('Please submit your payment for 99.95 immediately. ', 32, 5, '109.95')结果为:Please submit your payment for 109.95 immediately.

QUOTENAME()函数

这个函数和SQL Server对象名组合使⽤,以将结果传递给表达式。它只⽤于给输⼊的字符串加⼀对⽅括号,并返回新形成的字符串。如果参数包含保留的分隔符或者封装字符(⽐如引号或括号),这个函数将修改字符串,以便SQL Server能将结果字符串中的这类字符当成⽂本字符。如下⾯的例⼦所⽰,查询的结果如图6-10所⽰。

SELECT QUOTENAME(COLUMN_NAME) AS ColumnName FROM INFORMATION_SCHEMA. COLUMNS

数学函数

下表中列出的函数⽤于执⾏多种普通与特殊的数算,可以执⾏代数、三⾓、统计、估算与财政运算等运算。

函 数

ABS()ACOS()ASIN()ATAN()ATN2()CEILING()COS()COT()

DEGREES()EXP()FLOOR()LOG()LOG10()PI()

POWER()RADIANS()RAND()ROUND()SIGN()SIN()SQRT()SQUARE()TAN()

返回⼀个数的绝对值

计算⼀个⾓的反余弦值,以弧度表⽰计算⼀个⾓的反正弦值,以弧度表⽰计算⼀个⾓的反正切值,以弧度表⽰计算两个值的反正切,以弧度表⽰返回⼤于或等于⼀个数的最⼩整数计算⼀个⾓的正弦值,以弧度表⽰计算⼀个⾓的余切值,以弧度表⽰将⼀个⾓从弧度转换为⾓度指数运算

返回⼩于或等于⼀个数的最⼤整数计算以2为底的⾃然对数计算以10为底的⾃然对数返回以浮点数表⽰的圆周率幂运算

将⼀个⾓从⾓度转换为弧度

返回以随机数算法算出的⼀个⼩数,可以接收⼀个可选的种⼦值对⼀个⼩数进⾏四舍五⼊运算,使其具备特定的精度

根据参数是正还是负,返回–1或者1计算⼀个⾓的正弦值,以弧度表⽰返回⼀个数的平⽅根返回⼀个数的平⽅

计算⼀个⾓正切的值,以弧度表⽰

说 明

元数据函数

这是⼀些⼯具函数,它们返回SQL Server配置细节、服务器与数据库设置细节的信息,包括⼀组⽤于返回不同对象的属性状态的通⽤以及专⽤函数,这些函数把对Master数据库中系统表以及⽤户数据库的查询封装在函数中。建议读者使⽤这些函数以及其他的系统函数,⽽不是⾃⼰创建对系统表的查询,以防今后SQL Server版本对模式进⾏更改。

排列函数

这些函数被⽤于以与结果集顺序⽆关的特定顺序,枚举已排序的或排在前⾯的结果集。

ROW_NUMBER()函数

ROW_NUMBER()函数根据作为参数传递给这个函数的ORDER BY⼦句的值,返回⼀个不断递增的整数值。如果ROW_NUMBER的ORDER BY的值和结果集中的顺序相匹配,返回值将是递增的,以升序排列。如果ROW_NUMBER的ORDER BY⼦句的值和结果集中的顺序不同,这些值将不会按顺序列出,但它们表⽰ROW_NUMBER函数的ORDER BY⼦句的顺序。如下⾯的例⼦和结果所⽰:

SELECT ProductCategoryID ,Name

,ROW_NUMBER() OVER (ORDER BY Name) AS RowNumFROM Production.ProductCategoryORDER BY Name

由于ROW_NUMBER()调⽤中的ORDERBY⼦句和查询结果的顺序匹配,所以对这些结果按顺序列出,如下图所⽰:不过,在函数调⽤中使⽤另⼀个ORDER BY⼦句时,这些值就是⽆序的了。

SELECT ProductCategoryID ,Name

,ROW_NUMBER() OVER (ORDER BY Name) AS RowNumFROM Production.ProductCategory

ORDER BY ProductCategoryID

这是了解如何使⽤ORDER BY⼦句对结果进⾏排序的有效⽅法。如下图所⽰:

RANK()与DENSE_RANK()函数

这两个函数与ROW_NUMBER()函数类似,因为它们都返回⼀个基于ORDER BY⼦句的值。不过这些值不⼀定永远是唯⼀的。排列值对于所提供的ORDER BY⼦句中的重复结果⽽⾔也是重复的,⽽且唯⼀性是仅仅基于ORDER BY列表中的唯⼀值的。这些函数⽤不同的⽅法来处理重复的值。RANK()函数保留列表中⾏的位置序号,对于每个重复的值,该函数会跳过下⾯与其相邻的值,于是就可以将下⼀个不重复的值保留在正确的位置上。

其⾏为类似于短跑⽐赛中的并列成绩。例如刘翔与Dayron Robles(古巴)在110栏的⽐赛中都跑出了12’92的成绩,那他们就是并列第⼀,⽽其后的⼀名选⼿将会获得第三名的成绩。

SELECT ProductID ,Name ,ListPrice

,RANK() OVER (ORDER BY ListPrice DESC) AS [Rank]FROM Production.ProductORDER BY [Rank]

注意在下图的结果列表中,重复的价格值所对应的结果是相同的,⽽每个连接之后的值都被跳过了。⽐如,产品\"Road-150 Red, 52\"和\"Road-150 Red, 56\"都排在第1,⽽接下来的⾏\"Mountain-100 Silver,38\"就排在第6了。

DENSE_RANK()函数的⼯作⽅式与RANK()函数相同,不过它不会跳过每个连接后的值,这样就不会有值被跳过了,但是在连接处排列序号位置将会丢失。

SELECT ProductID ,Name ,ListPrice

,DENSE_RANK() OVER (ORDER BY ListPrice DESC) AS [Rank]FROM Production.ProductORDER BY [Rank]

下图的结果重复了排列值,但是不会跳过列中的任何数字。

NTILE(n)函数

这个函数也⽤于对结果进⾏排列,并返回⼀个整型的排列值,但是它不会对结果以唯⼀的排列顺序进⾏枚举,⽽是将结果切分为有限数量的排列组。⽐如,⼀个表有10

000⾏,使⽤1000为参数值调⽤NTILE()函数,即NTILE(1000),并将结果分成以10为单位的1000个组,每个组赋予相同的排列值。和本节讨论的其他排列函数⼀样,NTILE()函数也⽀持OVER(ORDER BY…)语法。下⾯的例⼦根据产品价格,按照从⾼到低的顺序把Product表分为50组产品:

SELECT ProductID ,Name ,ListPrice

,NTILE(50) OVER (ORDER BY ListPrice DESC) AS GroupedProductsFROM Production.ProductORDER BY GroupedProducts

结果为:

安全函数

与安全相关的函数返回SQL Server⽤户的⾓⾊成员和权限信息。这类函数也包括⼀组管理事件与跟踪的函数。下表显⽰了这些函数:函 数

fn_trace_geteventinfo()fn_trace_getfilterinfo()fn_trace_getinfo()fn_trace_getable()HAS_DBACCESS()IS_MEMBER()

IS_SRVROLEMEMBER()SUSER_SID()SUSER_SNAME()USER_ID()USER_NAME()

说 明

为指定的跟踪ID返回⼀个填充事件信息的表类型值

为指定的跟踪ID返回⼀个填充与过滤器有关的信息的表类型值为指定的跟踪ID返回⼀个填充跟踪信息的表类型值为指定的跟踪ID返回⼀个填充⽂件信息的表类型值

返回⼀个表明当前⽤户是否有访问指定数据库权限的标志

返回⼀个表明当前⽤户是Windows组⽤户还是SQL Server⽤户的标志返回⼀个表明当前⽤户是否是数据库服务器⾓⾊成员的标志

返回指定⽤户的登录名的安全ID,或者(如果参数被忽略)返回当前⽤户的安全ID。返回指定⽤户的⽤户ID,或者(如果参数被忽略的话)返回当前⽤户的⽤户ID

返回指定安全ID的登录名。如果不提供任何安全ID,则返回当前⽤户的登录名返回指定⽤户名的⽤户ID,或者(如果参数被忽略的话)返回当前⽤户的⽤户ID返回指定⽤户ID的⽤户名

系统函数与系统变量

本节讨论具有多种⽤途的⼯具函数,包括值⽐较、值类型测试等功能。这个类别的函数也包罗了其他函数:函 数

APP_NAME()COALESCE()

COLLATIONPROPERTY()CURRENT_TIMESTAMP()C1UJRRENT_USER()DATALENGTH()fn_helpcollations()

fn_servershareddrives()fn_virtualfilestats()FORMATMESSAGE()GETANSINULL()HOST_ID()

说 明

返回与当前连接相关联的应⽤程序的名字

从以逗号分隔的表达式列表中返回第⼀个⾮空值

返回⼀个特定字符集排序规则的特定属性的值。这些属性包括CodePage、LCID、ComparisonStyle返回当前⽇期与时间。和GETDATE()函数是同义的。这个函数的存在只是为了与ANSI-SQL兼容返回当前⽤户的名字。与USER_NAME()函数相同

返回存储或处理⼀个值所需的字节数。对于ANSI字符串类型,这个函数返回的值与LEN()函数相同,但对于其他数据类型⽽⾔就可能不⼀定相同了返回⼀个填充有由当前SQLSewer版本⽀持的字符集排序规则的表类型值返回⼀个填充有服务器共享的驱动列表的表类型值

返回⼀个填充有包括⽇志⽂件在内数据库⽂件的I/O状态的表类型值

从sysmessages表中为指定的信息代码和以逗号分隔的参数列表返回错误信息

根据ANSLNULL_DFLT_ON与ANSLNULL_DFLT_OFF数据库设置返回数据库的可空性设置返回当前会话的⼯作站ID

HOST_ID()HOST_NAME()

IDENT_CURRENT()IDENT_INCR()IDENT_SEED()IDENTITY()ISDATE()ISNULL()

ISNUMERIC()NEWID()

NULLIF()

PARSENAME()PERMISSIONS()ROWCOUNT_BIG()SCOPE_IDENTITY()SERVERPROPERTY()SESSION_USER

SESSIONPROPERTY()STATS_DATE()SYSTEM_USERUSER_NAME()

返回当前会话的⼯作站ID返回当前会话的⼯作站名

返回最后⼀个为指定的表⽣成的标识(ID)值。与会话、范围⽆关返回最后⼀次创建的标识(ID)列中定义的增量值

返回最后⼀次创建的标识(ID)列中定义的种⼦值

⽤在SELECT…INTO语句中,在⼀个列中插⼊⾃动⽣成的标识值返回⼀个表明指定的值是否可被转换为⽇期值的标志

判断指定的值是否是空值,然后返回⼀个事先提供的替代值返回⼀个表明指定的值是否可被转换为数字值的标志

返回⼀个新⽣成的UniqueIdentifier类型的值。这是⼀个128位的整型、全球唯⼀的值,通常以字母或数字⼗六进制来表⽰(如DE6247·C2E242DB-8CE8·A787E505D7EA)。这个类型经常被⽤作复制的和半连接系统中的主键.两个特定的参数的值如果是相同的,则返回NULL返回⼀个具有4部分对象名的特定部分

返回⼀个整型值,该值是⼀个表⽰当前⽤户在指定的数据库对象上权限或者权限组合的位映像

与@@RowCount变量⼀样,这个函数返回被最后⼀条语句修改或返回的⾏数量。返回值类型是bigint与@@IDENTIY变量⼀样,这个函数返回在当前会话与范围内的最后⼀次⽣成的标识值

返回⼀个表⽰服务器属性状态的标记。属性包括Collation、Edition、EngineEdition、InstanceName、IsClustered、IsFullTextInstalled、IsIntegrated-SecurityOnly、IsSingleUser、IsSyncWithBackup、LicenseTYpe、MachineName、NumLicenses、ProcessID、ProductLevel、ProductVersion、ServerName返回当前⽤户名。调⽤本函数不需要括号

返回表⽰⼀个会话属性状态的标记。属性包括:ANSL_NULLS,ANSI_PADDING,ANSL_WARNINGS,ARITHABORT,CONCAT_NULL_YIELDS_NULL,NUMERIC_ROUNDABORT,QUOTED_IDENTIFIER返回指定的索引统计信息最后⼀次被更新的时间返回当前⽤户名。调⽤本函数不需要括号

为⼀个指定的⽤户ID返回⽤户名。如果没有提供ID号则返回当前的数据库⽤户

COALESCE()函数

COALESCE()函数是⾮常有⽤的,它返回其参数中第⼀个⾮空表达式。它能够节省颇多IF或者CASE分⽀逻辑。以下例⼦⽤产品数据填充⼀个表,每个产品最多有3种价格:

CREATE TABLE #ProductPrices (ProductName varchar(25), SuperSalePrice Money NULL,SalePrice Money NULL, ListPrice Money NULL) GO

INSERT INTO #ProductPrices VALUES('Standard Widget', NULL, NULL, 15.95) INSERT INTO #ProductPrices VALUES('Economy Widget', NULL, 9.95, 12.95) INSERT INTO #ProductPrices VALUES('Deluxe Widget', 19.95, 20.95, 22.95) INSERT INTO #ProductPrices VALUES('Super Deluxe Widget', 29.45, 32.45, 38.95) INSERT INTO #ProductPrices VALUES('Executive Widget', NULL, 45.95, 54.95) GO

所有的产品都有定价,有些有销售价,有些还有促销价。⼀项产品的当前价格是所有⼰有价格的最低价,或者在读取每个价格列时以列出顺序读到的第⼀个⾮空值:

SELECT ProductName, COALESCE(SuperSalePrice, SalePrice, ListPrice) AS CurrentPriceFROM #ProductPrices

这个⽅法⽐使⽤多⾏分⽀与判断逻辑要简洁得多,⽽结果也是同样简单,如下图所⽰:

DATALENGTH()函数

DATALENGTH()函数返回⼀个⽤于对值进⾏管理的字节数,这有助于揭⽰不同数据类型间的⼀些有趣差别。当把varchar类型传递给DATALENGTH()和LEN()函数时,它们将返回相同的值:

DECLARE @Value varchar(20) SET @Value = 'abc'

SELECT DATALENGTH(@Value) SELECT LEN(@Value)

这些语句的返回值都为3。因为varchar类型使⽤了3个单字节字符来存储三个字符的值。然⽽,如果使⽤nVarchar类型来管理相同长度的值,就要占⽤多⼀倍的字节:

DECLARE @Value nvarchar(20) SET @Value = 'abc'

SELECT DATALENGTH(@Value) SELECT LEN(@Value)

DATALENGTH()函数返回值为6,因为每个使⽤Unicode字符集的字符都要占⽤2个字节。LEN()函数返回值为3,因为这个函数返回字符数,不是字节数。以下是⼀个有趣的测试:要存储⼀个值为2的整型变量,要占⽤多少个字节?⽽如果要存储⼀个值为20亿的整型变量,⼜将占⽤多少个字节呢?试⼀下:

DECLARE @Value1 int, @Value2 intSET @Value1 = 2

SET @Value2 = 2000000000 SELECT DATALENGTH(@Value1) SELECT LEN(@Value1)

SELECT DATALENGTH(@Value2) SELECT LEN(@Value2)

在这两种情况下,DATALENGTH()函数都返回4。因为int类型不论值是多少,总是使⽤4个字节。LEN()函数本质上将整型值当成已转换成字符型的数据来处理,所以,在这个例⼦中,它分别返回1和10,即值的位数。

在下表中的全局系统变量都将返回int类型的值。这些变量可⽤于存储过程和其他实现定制业务逻辑的编程对象。

变 量

@@ERROR@@IDENTITY@@ROWCOUNT@@TRANCOUNT

当前会话最后⼀次发⽣的错误代码当前会话最后⼀次⽣成的标识值

当前会话中最后⼀次返回结果集的执⾏操作所返回的⾏数

当前会话中活动的事务数。这是在执⾏相关的COMMIT TRANSACTION或者ABORT TRANSACTION语句之前嵌套的多个BEGIN

说 明

@@TRANCOUNT

当前会话中活动的事务数。这是在执⾏相关的COMMIT TRANSACTION或者ABORT TRANSACTION语句之前嵌套的多个BEGINTRANSACTION语句的结果

系统统计变量

下表描述了⽤于确定数据库系统使⽤信息与环境信息的管理⼯具:变 量

@@CONNECTIONS@@CPU_BUSY@@IDLE

@@IO_BUSY

@@PACK_RECEIVED@@PACK_SENT

@@PACKET_ERRORS@@TIMETICKS

@@TOTAL_ERRORS@@TOTAL_READ@@TOTAL_WRITE

说 明

返回打开连接的次数

从上次启动服务器开始,SQL Server⼀共⼯作的毫秒数从上次启动服务器开始,SQL Server⼀共空闲的毫秒数从上次启动服务器开始,SQL Server⼀共处理I/0的毫秒数从上次启动服务器开始,SQL Server⼀共收到的⽹络数据包数从上次启动服务器开始,SQL Server⼀共发送的⽹络数据包数从上次启动服务器开始,SQL Server⼀共收到的⽹络数据包错误数每个时钟滴答有多少毫秒

从上次启动服务器开始,SQL Server⼀共收到的磁盘I/O错误数从上次启动服务器开始,SQL Server⼀共进⾏的物理磁盘读取次数从上次启动服务器开始,SQL Server⼀共进⾏的物理磁盘写⼊次数

⼩结

函数⽤于实现业务逻辑,并且能够将编程功能带⼊查询中。许多有⽤⽽且强⼤的函数是T-SQL的标准功能。和⾯向过程、⾯向对象语⾔中的函数⼀样,SQL函数也将程序功能封装到⼀个简单的可重⽤的包中,这就减少了查询设计⼈员的很多⼯作。由于Transact-SQL是⾯向任务的语⾔,⽽不是过程语⾔。虽然函数可以进⾏过程编程,可以在查询中构建颇为复杂的逻辑,但是SQL语⾔的优势在于让设计⼈员表达出设计意图,⽽不是完成⼀项任务的确切步骤与⽅法。只要使⽤⽅法正确,这些步骤和⽅法都可以由函数来实现。

在T-SQL中,参数⽤于将值传递给函数,⼤多数函数的返回结果是⼀个标量,或者说单⼀值。函数分为确定性函数与⾮确定性函数。在使⽤相同的参数时,确定性函数总是返回相同的值,⽽⾮确定性函数的返回值则与其他资源有关,所以SQL Server必须显式地执⾏这种函数。因此,在定制的SQL编程对象中,对⾮确定性函数的使⽤是有的。

SQL函数执⾏种类繁多的重要任务,包括数算、⽐较、⽇期解析与操纵、⾼级字符串操纵等。

因篇幅问题不能全部显示,请点此查看更多更全内容

Copyright © 2019- 99spj.com 版权所有 湘ICP备2022005869号-5

违法及侵权请联系:TEL:199 18 7713 E-MAIL:2724546146@qq.com

本站由北京市万商天勤律师事务所王兴未律师提供法律服务