技术开发 频道

SQL Server 2008 对 T-SQL 语言的增强

IT168技术文档】

    Microsoft SQL Server 2008 对 T-SQL 语言进行了进一步增强。为了让开发人员尽快了解这些变化,我们针对 2007 年 6 月 CTP 版本的 SQL Server 2008 中的 T-SQL 语言的新增功能进行了分析和尝试。本文描述自 SQL Server 2008 CTP1 以来这些语言增强和变化。

    1、T-SQL 行构造器

    T-SQL 行构造器(Row Constructors)用来在 INSERT 语句中一次性插入多行数据。例如:

CREATE TABLE #a ( Column1 nvarchar(max), Column2 nvarchar(max) ); GO INSERT INTO #a VALUES ( ('1', '1'), ('2', '2') ); SELECT * FROM #a; GO DROP TABLE #a; GO

    经过增强后的 INSERT 语句的语法结构如下。

[ WITH <common_table_expression> [ ,...n ] ]
INSERT
[ TOP ( expression ) [ PERCENT ] ]
[ INTO ]
{ <object> | rowset_function_limited
[ WITH ( <Table_Hint_Limited> [ ...n ] ) ]
}
{
[ ( column_list ) ]
[ <OUTPUT Clause> ]
{ VALUES ( ( { DEFAULT | NULL | expression } [ ,...n ] ) [ ,...n ] )
| derived_table
| execute_statement
| <dml_table_source>
| DEFAULT VALUES
}
}
[; ]

<object> ::=
{
[ server_name . database_name . schema_name .
| database_name .[ schema_name ] .
| schema_name .
]
table_or_view_name
}

<dml_table_source> ::=
SELECT <select_list>
FROM ( <dml_statement_with_output_clause> )
[AS] table_alias [ ( column_alias [ ,...n ] ) ]
[ WHERE <search_condition> ]
[ OPTION ( <query_hint> [ ,...n ] ) ]

    2. FORCESEEK 提示

    FORCESEEK 是一个新的表提示(Table Hints),它用来指定 SQL Server 查询优化程序如何更高效的执行查询。该提示指示优化程序对查询引用的表和视图通过索引检索来作为唯一的查询执行访问路径。也就是强制通过索引检索数据。例如:

USE tempdb; GO DROP TABLE t; GO CREATE TABLE t(i int UNIQUE, j int, vc varchar(100)); CREATE INDEX t_vc ON t(vc); GO DECLARE @p1 int, @p2 int, @p3 int, @p4 int, @p5 int; SELECT * FROM t WHERE i IN (@p1, @p2, @p3, @p4, @p5); GO DECLARE @p1 int, @p2 int, @p3 int, @p4 int, @p5 int; SELECT * FROM t WITH (FORCESEEK) WHERE i IN (@p1, @p2, @p3, @p4, @p5); GO SELECT * FROM t WHERE vc LIKE 'Test%'; GO SELECT * FROM t WITH (FORCESEEK) WHERE vc LIKE 'Test%'; GO DECLARE @vc varchar(100); SELECT * FROM t WHERE vc LIKE @vc; GO DECLARE @vc varchar(100); SELECT * FROM t WITH (FORCESEEK) where vc like @vc; GO

    3. GROUPING SETS

    新的 T-SQL 对 GROUP BY 子句增加了 GROUPING SETS, ROLLUP 和 CUBE 操作符。还有一个新的函数 GROUPING_ID(),它相比 GROUPING() 函数返回更多分组级别的信息。WITH ROLLUP, WITH CUBE 和 ALL 等非 ISO 标准语法已经不再有效。

  4. 兼容性级别

    新的 ALTER DATABASE SET COMPATIBILITY_LEVEL 语法替换了 sp_dbcomplevel 存储过程。它用来设置特定数据库的兼容性级别。其语法形式为:
ALTER DATABASE database_name SET COMPATIBILITY_LEVEL = { 80 | 90 | 100 }
    您可以为 database_name 为名称的数据库设置特定兼容性级别。80、90 和 100 分别代表 SQL Server 2000、SQL Server 2005 和 SQL Server 2008。

    5. 用户自定义表数据类型

    现在,SQL Server 提供一种新的用户自定义数据类型——自定义表数据类型(User-defined Table Types)。它可以作为参数提供给语句、存储过程或者函数。您还可以为它创建唯一约束和主键。

    请使用 CREATE TYPE 语句创建这种数据类型。如:
USE AdventureWorks; GO /* Create a user-defined table type */ CREATE TYPE LocationTableType AS TABLE ( LocationName VARCHAR(50) , CostRate INT ); GO
    对于表类型,有如下约束:
    1、用户自定义表类型不能作为表的列或者结构化用户自定义类型的域。
    2、基于用户自定义表类型的别名类型。
    3、不允许 NOT FOR REPLICATION 选项。
    4、CHECK 约束需要一个计算列。
    5、在计算列上的主键必须包含 NOT NULL 和 PERSISTED 约束。
    6、不能在用户自定义表类型上创建非簇索引。除非索引是创建 PRIMARY KEY 或 UNIQUE 约束的返回值。
    7、不能指定 DEFAULT 值。
    8、一旦用户自定义表类型被创建,则它就无法更改。
    9、如果没有定义用户自定义表类型上的计算列,则用户自定义函数无法调用。

    6. 表值参数

    数据库引擎现在支持一种新的参数类型来引用用户自定义表类型(参考 5)。表值参数可以发送更多的 SQL Server 数据。下面的示例展示了如何使用表值参数。
USE AdventureWorks; GO /* Create a table type. */ CREATE TYPE LocationTableType AS TABLE ( LocationName VARCHAR(50) , CostRate INT ); GO /* Create a procedure to receive data for the table-valued parameter. */ CREATE PROCEDURE usp_InsertProductionLocation @TVP LocationTableType READONLY AS SET NOCOUNT ON INSERT INTO [AdventureWorks].[Production].[Location] ([Name] ,[CostRate] ,[Availability] ,[ModifiedDate]) SELECT *, 0, GETDATE() FROM @TVP; GO /* Declare a variable that references the type. */ DECLARE @LocationTVP AS LocationTableType; /* Add data to the table variable. */ INSERT INTO @LocationTVP (LocationName, CostRate) SELECT [Name], 0.00 FROM [AdventureWorks].[Person].[StateProvince]; /* Pass the table variable data to a stored procedure. */ EXEC usp_InsertProductionLocation @LocationTVP; GO
    7. MERGE 语句

    这个新增的 Transaction SQL 语句在一个基于源数据连接结果集的目标表上执行 INSERT、UPDATE 和 DELETE 操作。该语法允许您将一个数据源连接到目标表或视图上。然后在连接后的结果集上执行多种操作。

    MERGE 的语法为:
[ WITH <common_table_expression> [,...n] ]
MERGE
[ TOP ( expression ) [ PERCENT ] ]
[ INTO ] target_table [ [ AS ] table_alias ]
[ WITH ( <merge_hint> ) ]
USING <table_source>
ON <search_condition>
[ WHEN MATCHED [ AND <search_condition> ]
THEN <merge_matched> ]
[ WHEN [TARGET] NOT MATCHED [ AND <search_condition> ]
THEN <merge_not_matched> ]
[ WHEN SOURCE NOT MATCHED [ AND <search_condition> ]
THEN <merge_ matched> ]
<output_clause>
[ OPTION ( <query_hint> [ ,...n ] ) ]
;
<merge_hint>::=
{ [ <table_hint_limited> [ ,...n ] ]
[ [ , ] INDEX ( index_val [ ,...n ] ) ] }

<table_source> ::=
{
table_or_view_name [ [ AS ] table_alias ] [ <tablesample_clause> ]
[ WITH ( table_hint [ [ , ]...n ] ) ]
| rowset_function [ [ AS ] table_alias ]
[ ( bulk_column_alias [ ,...n ] ) ]
| user_defined_function [ [ AS ] table_alias ]
| OPENXML <openxml_clause>
| derived_table [ AS ] table_alias [ ( column_alias [ ,...n ] ) ]
| <joined_table>
| <pivoted_table>
| <unpivoted_table>
}

<merge_matched>::=
{ UPDATE SET <set_clause> | DELETE }

<set_clause>::=
{ column_name = { expression | DEFAULT | NULL }
| { udt_column_name. { { property_name = expression
| field_name = expression }
| method_name ( argument [ ,...n ] ) } }
| column_name { .WRITE ( expression , @Offset , @Length ) }
| @variable = expression
} [ ,...n ]

<merge_not_matched>::=
INSERT [ ( <column_list> ) ]
{ VALUES ( <values_list> )
| DEFAULT VALUES }

<output_clause>::=
{
[ OUTPUT <dml_select_list> INTO { @table_variable | output_table }
[ (column_list) ] ]
[ OUTPUT <dml_select_list> ]
}
<dml_select_list>::=
{ <column_name> | scalar_expression } [ [AS] column_alias_identifier ]
[ ,...n ]

<column_name> ::=
{ DELETED | INSERTED | from_table_name } . { * | column_name }
| $ACTION
    示例:在一条 SQL 语句中使用 WHERE 在一张表上执行 UPDATE 和 DELETE 操作
USE AdventureWorks; GO MERGE Production.ProductInventory AS pi USING (SELECT ProductID, SUM(OrderQty) FROM Sales.SalesOrderDetail sod JOIN Sales.SalesOrderHeader soh ON sod.SalesOrderID = soh.SalesOrderID AND soh.OrderDate = GETDATE() GROUP BY ProductID) AS src (ProductID, OrderQty) ON (pi.ProductID = src.ProductID) WHEN MATCHED AND pi.Quantity - src.OrderQty <> 0 THEN UPDATE SET pi.Quantity = pi.Quantity - src.OrderQty WHEN MATCHED AND pi.Quantity - src.OrderQty = 0 THEN DELETE;
    这个示例是一个非常典型的销售定货库存问题。这个示例很简单,表达的意思就是:如果某一个产品产生了销售定单数据,则
将其对应的产品库存除去该销售定单所产生的数量,如果当前库存数量与该销售定单数量相同,则从库存表中删除该产品的库存纪录。

    我们看到,利用 MERGE 语句可以将复杂的 SQL 语句简化。它比起 IF、CASE 等更加灵活和强大。

    结论

    Microsoft SQL Server 2008 对事务性 SQL 语言做了一些增强,提高了查询效率。使得 SQl Server 成为大中型企业数据库的首先产品。SQL Server 2008 将伴随 Visual Studio 2008 一起发布,开发人员提前了解这些信息有助于在 SQL Server 的新版本发布后快速建立基于该版本的企业级应用程序。
0
相关文章