本文是SQL Server 2012 T-SQL系列文章的第四部分,也是最后一部分。您可以参考了解本系列文章的其它部分:数据值的乐趣,T-SQL函数和T-SQL格式转换。 你可能经常想从结果集中的前面行或者从某一行后面的行访问数据,但是还不想创建自连接查询。这种情况正是“LAG”函数和“LEAD”函数的用武之地。
“LAG”函数支持你从前面的行获取数据,而“LEAD”函数为你提供从后面的行获取数据的功能。你可以在当前行比较那些数据的值。 LAG 与 LEAD 我们来通过一个例子看看这两个函数是如何使用的。下面的“SELECT”语句从“SalesOrderHeader”表获取数据,并基……
我们一直都在努力坚持原创.......请不要一声不吭,就悄悄拿走。
我原创,你原创,我们的内容世界才会更加精彩!
【所有原创内容版权均属TechTarget,欢迎大家转发分享。但未经授权,严禁任何媒体(平面媒体、网络媒体、自媒体等)以及微信公众号复制、转载、摘编或以其他方式进行使用。】
微信公众号
TechTarget
官方微博
TechTarget中国
本文是SQL Server 2012 T-SQL系列文章的第四部分,也是最后一部分。您可以参考了解本系列文章的其它部分:数据值的乐趣,T-SQL函数和T-SQL格式转换。
你可能经常想从结果集中的前面行或者从某一行后面的行访问数据,但是还不想创建自连接查询。这种情况正是“LAG”函数和“LEAD”函数的用武之地。“LAG”函数支持你从前面的行获取数据,而“LEAD”函数为你提供从后面的行获取数据的功能。你可以在当前行比较那些数据的值。
LAG 与 LEAD
我们来通过一个例子看看这两个函数是如何使用的。下面的“SELECT”语句从“SalesOrderHeader”表获取数据,并基于年度分组信息:
SELECT YEAR(OrderDate) AS OrderYear, SUM(SubTotal) AS Subtotal, LAG(SUM(SubTotal), 1, 0) OVER (ORDER BY YEAR(OrderDate)) AS LastYear, LEAD(SUM(SubTotal), 1, 0) OVER (ORDER BY YEAR(OrderDate)) AS NextYear FROM Sales.SalesOrderHeader GROUP BY YEAR(OrderDate) ORDER BY YEAR(OrderDate); |
对于每一年的数据,T-SQL语句都提取了“Subtotal”值的小计,最后还生成了前面所有年和本年的总计。为了从前面的年度提取总计,该语句在第三列表达式使用了“LAG”函数。该函数有三个参数,第一个参数是返回运算值的表达式,本例中是“SubTotal”值的总计。第二个参数指出了待返回的行。因为本例中设置的是“1”,所以数据会从前一行取出来。最后一个参数指定如果前面行为“NULL”时的返回值。本例中设置的是“0”。
“LAG”函数还需要“OVER”语句来在该函数应用之前判断数据的顺序。这就确保你取到的是正确的行。
要从当前行后面的行提取数据,本例中的“SELECT”语句使用了“LEAD”函数,它的用法与“LAG”函数类似,只是先前(下一行)移动结果集,而不是向后(上一行)。由于我们使用了这两个函数,该“SELECT”语句返回结果如下:
每一行都包含有当年、上一年、下一年的总销量。例如,在第一行中,“LastYear”值是“0.00”。因为它前面没有数据行了,所以该年的总计是“NULL”。根据我们前面的介绍,“LAG”函数把“NULL”转换成了“0.00”。对于最后一行处理也类似。因为它代表了结果中可用的最后一年,所以“NextYear”的值就是“0.00”,也是从“NULL”转换而来的。
RESULTS SETS
在SQL Server 2012之前,“EXECUTE”语句的“WITH”从句只支持“RECOMPILE”选项。然而,该从句现在还支持“RESULTS SETS”选项,可以帮助更好地控制存储过程返回的结果集。你可以用这个选项实现的功能是,重新定义结果集定义,而无需修改存储过程本身。
例如,“AdventureWorks2012”数据库中有个存储过程“uspGetEmployeeManagers”。下面的表展示了该存储过程返回的列以及它们的数据类型。(“Name”数据类型是用户定义的数据类型,基于“NVARCHAR(50)”内建数据类型定义的。)
通过使用“ RESULT SETS”选项,你可以修改列名,数据类型(如果支持隐式转换的话),排序以及为空属性。例如,假如你想缩减存储过程返回的列名,并修改几个数据类型。你可以在运行“EXECUTE”语句时使用“ RESULT SETS”选项,请参考下面例子:
EXECUTE uspGetEmployeeManagers 100 WITH RESULT SETS ( ( RecursLevel INT, EmplID INT, FName NVARCHAR(50), LName NVARCHAR(50), OrgNode HIERARCHYID, MgrFName NVARCHAR(50), MgrLName NVARCHAR(50) ) ); |
当你在“WITH”语句中带上了“result set”选项,你必须同时包含列名和数据类型。排序和为空属性是可选的。在本例中,我修改了列名和几个数据类型。下表展示了该存储过程返回的结果。
你可以看到,现在结果中的列名与存储过程原来定义的不一样了。(数据类型的变化在结果集中没有视觉上的变化。)你可以很容易地提供不同的列名集和数据类型。但是同样,那些数据类型必须支持从原类型进行隐式转换。
THROW
过去,如果我们想以“TRY…CATCH”的结果返回错误信息,你要使用“RAISEERROR”生成该信息,但是Transact-SQL现在支持使用“THROW”语句,你可以在“CATCH”块中重新抛出异常,屏蔽原始信息。要实现这一功能,你只需要指定“THROW”关键字,不需要任何参数。下面的例子展示了带有“THROW”语句“CATCH”块的用法:
BEGIN TRY SELECT CONVERT(INT, 'books'); END TRY BEGIN CATCH THROW; END CATCH; |
“THROW”语句重新抛出了由“CATCH”块捕获的原始错误,这样错误可以在应用层面进行处理。在上面的例子中“SELECT”语句出错了,因为字符串值不能被转换。结果“THROW”就返回了如下错误信息:
Msg 245, Level 16, State 1, Line 2 把varchar值‘books’转换为int数据类型时失败。 |
“THROW”语句还支持指定参数,方便你返回自定义信息。要实现这一功能,你需要提供一个消息编号,消息文本内容以及与消息关联的状态。你必须使用系统预定义消息之外的消息编号与消息进行关联。你可以使用“50000”到“2147483647”之间的数字。下面的“CATCH”块包含有“THROW”语句,其中包含自定义信息:
BEGIN TRY DECLARE @string VARCHAR(50) = 'books' DECLARE @message VARCHAR(100) = CONCAT('You cannot convert "', @string, '" to the INT data type.') SELECT CONVERT(INT, @string); END TRY BEGIN CATCH THROW 55000, @message, 1; END CATCH |
“THROW”语句中的第一个参数是数值“55000”。它是消息编号,在可接受的范围内。第二个参数是消息本身,在本例中是通过“ @message”变量传递的内容。第三个参数是“1”,它表示消息关联的状态。你可以指定的数值范围是“0”到“255”。“THROW ”语句返回如下消息:
Msg 55000, Level 16, State 1, Line 8 You cannot convert "books" to the INT data type. |
你可以看到,该结果包含有消息和状态代码,还有错误等级和行号。在本例中,行号对应的代码位置是“THROW”语句,而不是实际产生错误的位置。然而,如果你留意前面例子中的返回内容的话,你就会发现前面返回的信息是包含了准确的错误行号位置的。这是因为当你使用“THROW”语句并不指定任何参数时,它只是把原始错误重新抛出来而已。
与T-SQL一起发展
如你所见,SQL Server 2012为Transact-SQL引入了许多增强功能。你可以找到新的系统存储过程和动态管理视图,还有大量其它更新。当然,所有这些变更也有不利的一面,不推荐使用的功能在未来的SQL Server版本中将不再被支持。你应当在了解新功能的同时意识到这一点。但是,对于那些最新Transact-SQL变化中特别有趣的部分,在这些文章中介绍的这些语言元素应该对许多新功能提供了一个很好的概览,这些功能在现在一级可预见的将来肯定是都支持的。
翻译
相关推荐
-
OpenWorld18大会:Ellison宣布数据库的搜寻和破坏任务
在旧金山举行的甲骨文OpenWorld 2018大会中,甲骨文首席技术官(CTO)兼创始人Larry Elli […]
-
ObjectRocket着力发展Azure MongoDB服务
MongoDB吸引了微软公司的注意力,微软公司计划针对运行于该公司2017年发布的Azure Cosmos D […]
-
数据库和数据仓库的区别在哪儿?
目前,大部分数据仓库还是用数据库进行管理。数据库是整个数据仓库环境的核心,是数据存放的地方和提供对数据检索的支持。
-
如何使用服务来平衡Oracle RAC 数据库工作负载
为不同的应用程序配置不同的服务,DBA可以更有效地平衡集群工作负载,在Oracle RAC数据库环境下实现更好的应用程序性能。