首页 > 大数据 > 正文

SQL Server 2012中新T-SQL命令的使用

2012-07-10 14:50:22  来源:TechTarget中国

摘要:SQL Server的每个版本在Transact-SQL(T-SQL)方面都会有些新的变化,这些变化会让程序员的工作变得更加轻松,同时也会实现SQL Server用户社区提出的一些需求。
关键词: SQL Server

    SQL Server的每个版本在Transact-SQL(T-SQL)方面都会有些新的变化,这些变化会让程序员的工作变得更加轻松,同时也会实现SQL Server用户社区提出的一些需求。当然SQL Server 2012也是如此。在本文中,我将介绍几个用户需要注意的新的T-SQL命令。


    WITH RESULT SETS (在 EXECUTE命令中)


    “WITH RESULT SETS”命令解决了困扰大多数人的问题,编写存储过程作为他们业务逻辑一部分的用户都遇到过这个问题:列名往往是不能改变的。


    假定你创建了一个存储过程,返回几列数据,都有指定的名称和数据类型。虽然你每次运行存储过程时,你都只能获得那些名称和数据类型的结果。但如果你修改存储过程,修改输出,就有可能出现与其它组件不兼容的情况(包括SQL Server内部的和外部的组件)。


    我们有很多种方法可以解决这个问题:例如,创建并行存储过程,返回新格式的结果,然后逐步把所有逻辑迁移到新存储过程中来。然而在迁移期间,一般需要维护两套存储过程,不管这个过程持续多久。


    “WITH RESULT SETS”的出现解决了这一问题,而且在我看来是更优雅的一种处理方式。它可以支持你在调用存储过程时,通过使用指令重新定义存储过程的结果集名称和类型,请看下面示例:


    EXEC myStoredProcedure 123


    上面命令正常会返回“int”类型列,名称是“Result_Code”.由于业务逻辑的变化,我们需要让列名称改为“ResultCode”.(可以采取的做法是:实行一个标准,规定列如何命名,且不允许出现下划线)。我们不需要修改存储过程本身,我们只需要修改存储过程的调用之处,请看下面命令:


    EXEC myStoredProcedure 123


    WITH RESULT SETS


    ([ResultCode] int NOT NULL)


    还有一个方法,你可以使用“WITH RESULT SETS”返回多个结果集:


    EXEC myStoredProcedure 123


    WITH RESULT SETS


    (


    ([ResultCode] int NOT NULL),([Result_Code] int NOT NULL)


    )


    这个命令会给客户端返回两个结果集--第一个结果集是“新格式”的,第二个结果集是“原来的格式”.这样你可以让客户端选择哪一个结果集更适合使用,这都是同一个命令返回来的。


    “OFFSET ”和“FETCH ”(在“ORDER BY”从句中使用)


    大部分SQL Server DBA发现他们自己都需要以分页形式提供结果。对于这个问题,有许多类似“半成品”的解决方案,从简单地把应用程序整个结果集本地缓存然后在本地做分页计算,到使用“NOT IN”或者其它非常消耗性能的命令等。


    新的“OFFSET ”命令带来了一种优雅的方法,在查询端做整体分页。我们来看看命令怎么写:


    SELECT [UserID], [UserName]


    FROM [UserTable]


    ORDER BY [Username] ASC


    OFFSET 10 ROWS


    FETCH NEXT 10 ROWS ONLY


    结果基本正是你所期望的:SQL Server从表中读取数据,跳过了查询返回的前十行,然后只返回接下来的十行数据。这比使用嵌套查询加上“TOP x”类型限制少了很多不便。


    要注意,当你使用“OFFSET/FETCH”提取结果时,结果会当成是一个独立的事务,而不是像游标那样的对象。比方说下面这种情况:


    1.你使用类似上面这样的命令取到了表中的前十行。


    2.当你处理这些行时,该表接受了其它插入语句,增加的行会出现在你查询的第一页中。


    3.你该取接下来的十行,但是你取到的接下来十行将包括新增到该表中的数据,而不是基于第一次查询得到的结果集中的下一个十行数据。


    在编写应用程序时要留意,确保你的数据分页方式定义的条件不会违背常理(或者,更糟糕的情况下,你可能会无意中创建引起数据完整性问题的条件)。


    THROW


    SQL Server中的错误处理通常是通过“RAISERROR ”命令实现的。然而,“RAISERREOR ”有几个限制:它只能返回“ sys.messages”中定义的错误码,尽管你可以使用大于50000的错误码来创建自定义错误类型。(默认是50000,但是你可以指定其它编码)。也就是说,这对于处理系统级错误是最有用的,但是对于具体涉及你数据库的错误就不是很合适了。新命令“THROW ”支持错误捕获操作,这样可以更好地适合T-SQL用户的应用。我们把它与“RAISERROR ”命令的方式进行比较,就可以看到它们彼此特点如何,哪种最适合你的情况。


    1.  最重要的一点:“RAISERROR ”总是产生新的异常,不管什么时候调用。所以在例程执行期间任何之前生成的异常(例如,一些CATCH块之外的异常)都会抛弃。“THROW ”可以重新抛出原异常,触发“CATCH”代码块,所以它可以提供该错误的更多上下文信息。


    2.“RAISERROR ”用来产生应用级的和系统级的错误代码。“THROW ”只产生应用级的错误(错误码大于等于50000的那部分)


    3.如果你使用错误码“50000”或者更大的错误码编号,“RAISERROR ”只能传递自定义错误消息;而“THROW ”支持传入任何想要的错误文本。


    4.“RAISERROR ”支持标记替代;“THROW ”不支持。


    5.“RAISERROR ”支持任何安全级别的错误;“THROW ”只支持安全级别16的错误。


    总而言之,设计“THROW ”命令主要是给T-SQL脚本和存储过程在你需要返回自定义错误时用的,这些错误是为你创建的应用程序专门自定义的。

    我经常能听到Oracle DBA对SQL Server DBA说:“你终于可以使用那个新功能特性了吗?为什么这么晚,我们Oracle用户已经使用很多年了。”每当这个时候,我恨不得找个地缝钻进去。不过现在Oracle用户们终于可以不再对SQL Server开发者趾高气昂了,因为我们有了“SEQUENCE”对象。


    序列号的功能多少有点类似标识列,只是它们没有绑定到特定表,而是绑定到了给定的模式对象。在创建的时候,该对象会遵从特定规则来定义序列。序列本身设计也不是本着唯一主键的思路,与标识列不同,标识列在整个上下文中智能使用一次--例如,它们可以被应用到表或者用作存储过程循环的一部分。


    我们一起来看一下:


    CREATE SEQUENCE mySchema.Identity


    START WITH 1


    INCREMENT BY 1


    MINVALUE 1


    NO MAXVALUE


    NO CYCLE;


    该命令会创建一个新的序列,从1开始,增量是1,没有最大值限制,而且不会从最小值(MINVALUE)再开始循环重复(CYCLE)。没有最大值本身就意味着不会有循环发生,但是我这么写只是想在这个例子中表示的更清晰一些:


    另外,也可以这么写:


    CREATE SEQUENCE mySchema.Identity2


    START WITH -10


    INCREMENT BY 1


    MINVALUE 1


    MAXVALUE 10


    CYCLE;


    该命令会启动一个序列,从“-10”开始,增量还是1,但最大值是10,达到最大值后会重新从1开始。这样的话,编号和行为序列比ID列更多了一点灵活。例如,你可以在多个表之间共享专门的数字序列,不需要手工编码控制递增(比如使用用户自定义函数实现)来实现。


    要使用序列的值,你可以使用“NEXT VALUE FOR”语句。下面是在“SELECT”语句中使用的一个例子:


    SELECT NEXT VALUE FOR mySchema.Identity as IdentityFromSequence;


    这个命令可以获取“mySchema.Identity”的当前序列值,然后该序列会按照定义规则自动递增。另一种使用形式是在“INSERT”语句中:


    INSERT myTable (myColumn)


    VALUES (NEXT VALUE FOR mySchema.Identity);


    你还可以在变量上下文中使用它:


    SET @myVariable=NEXT VALUE FOR mySchema.Identity;


    “TRY_CONVERT” 和 “TRY_PARSE”


    “TRY_CONVERT” 和 “TRY_PARSE”都是新增功能中比较小但是很有用的部分,它们会给转换数据类型带来很大方便。“TRY_CONVERT”把传入的值转换为有效的转换值。如果转换不成,它会返回“null”,而不会抛出错误。请看下面示例:


    SELECT TRY_CONVERT(DATETIME, 'This is not a date‘)


    上面命令会返回“null”.如果你把“null”值用作存储过程处理中的一部分,那么这一点很有用,因为你肯定不想传入值无效时程序被卡死。


    “TRY_PARSE”作为一个变量,它的功能与原来的“PARSE ”命令相同。微软推荐使用“PARSE ”把字符串转换为日期或者数字,而使用“CONVERT ”做更多普通的类型转换。


    DATEFROMPARTS


    该命令基于年月日值返回日期值。例如:


    SELECT DATEFROMPARTS (2012,05,1)


    该存储过程返回日期是2012年五月一日。


    IIF


    这个表达式是从Excel中移植过来的,它本质上是创建“CASE”语句的简写方式:


    SELECT IIF (1>2,'Impossible','Possible’)


    第一部分是待验证条件。第二部分是验证条件为真时返回的表达式;第三部分是验证条件为假时返回的表达式。要注意在“IIF”表达式中你最多只能嵌套十层,同样你也只能嵌套十层“CASE”语句。(坦白地讲,如果你嵌套超过十层,你真的需要重新思考你编写“T-SQL”语句的方式了。)


    CONCAT


    这是使用一个或多个值创建字符串的快捷方法,所有参数都会被隐式地转换为字符串。


    SELECT CONCAT(‘Once upon','a time',32+32)


    该命令返回结果为:


    Once upona time64


    要注意数字旁边缺少了空格。“CONCAT ”不会在表达式之间添加空格。


    另外还要注意返回类型很大程度上依赖于提供的参数,可能是“varchar”或者“nvarchar(max)”.通常“CONCAT ”会返回最适合该字符串和传入表达式整体长度的类型。例如:如果没有输入参数用作大对象类型,那么返回类型永远不会超过八千个字符。


    在这些新功能特性中,还有一点东西大家可以用。那些希望加强错误处理的用户有“THROW ”函数可以用了;那些需要自定义数据分页解决方案的用户现在有“OFFSET/FETCH”可以用了;那些希望以更优雅的方式查询重命名存储过程返回结果列的用户有“WITH RESULT SETS”可以用了;那些希望有更灵活的方法处理序列号的用户现在有“sequences”序列可以用了。
 


第三十五届CIO班招生
国际CIO认证培训
首席数据官(CDO)认证培训
责编:zhangyexi

免责声明:本网站(http://www.ciotimes.com/)内容主要来自原创、合作媒体供稿和第三方投稿,凡在本网站出现的信息,均仅供参考。本网站将尽力确保所提供信息的准确性及可靠性,但不保证有关资料的准确性及可靠性,读者在使用前请进一步核实,并对任何自主决定的行为负责。本网站对有关资料所引致的错误、不确或遗漏,概不负任何法律责任。
本网站刊载的所有内容(包括但不仅限文字、图片、LOGO、音频、视频、软件、程序等)版权归原作者所有。任何单位或个人认为本网站中的内容可能涉嫌侵犯其知识产权或存在不实内容时,请及时通知本站,予以删除。