2.4 开发方面
Microsoft SQL Server 2008 对 T-SQL语言进行了进一步增强,包括 T-SQL 行构造器、FORCESEEK表提示、GROUPING SETS、兼容性级别、用户自定义表数据类型、表值参数、MERGE语句等,下面将一一为你展现。
2.4.1 一次性插入多行数据
例如,以下的示例用INSERT语句在testTable表中一次插入了2行数据。
例2-1 一次插入多行数据
CREATE TABLE testTable ( Column1 nvarchar(10), Column2 nvarchar(10) ) GO INSERT INTO tesTable VALUES ( ('1', '1'), ('2', '2') )
2.4.2 FORCESEEK提示
FORCESEEK是一个新的表提示,它用来指定SQL Server查询优化程序如何更高效地执行查询。该提示指示优化程序对查询引用的表和视图通过索引检索来作为唯一的查询执行访问路径,也就是强制通过索引检索数据。例如如下的代码:
例2-2 FORCESEEK提示
USE testDB1; 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
2.4.3 GROUPING SETS
新的T-SQL对GROUP BY子句增加了GROUPING SETS、ROLLUP和CUBE操作符。还有一个新的函数GROUPING_ID(),它相比 GROUPING()函数返回更多分组级别的信息。WITH ROLLUP、WITH CUBE和ALL等非ISO标准语法已经不再有效。
2.4.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。
2.4.5 用户自定义表数据类型
现在,SQL Server 2008提供一种新的用户自定义数据类型——自定义表数据类型,它可以作为参数提供给语句、存储过程或者函数。你还可以为它创建唯一约束和主键。
使用CREATE TYPE语句创建这种数据类型,如下例所示。
例2-3 使用CREATE TYPE语句创建用户自定义表数据类型
USE testDB1; GO /*创建一个用户自定义表数据类型 */ CREATE TYPE newType AS TABLE ( comName VARCHAR(50), Rate INT ); GO
对于表类型,有如下约束:
(1)用户自定义表类型不能作为表的列或者结构化用户自定义类型的域。
(2)基于用户自定义表类型的别名类型。
(3)不允许NOT FOR REPLICATION选项。
(4)CHECK约束需要一个计算列。
(5)在计算列上的主键必须包含NOT NULL和PERSISTED约束。
(6)不能在用户自定义表类型上创建非簇索引。除非索引是创建PRIMARY KEY或UNIQUE约束的返回值。
(7)不能指定DEFAULT值。
(8)一旦用户自定义表类型被创建,则它就无法更改。
(9)如果没有定义用户自定义表类型上的计算列,则用户自定义函数无法调用。
2.4.6 表值参数
数据库引擎现在支持一种新的参数类型来引用用户自定义表类型,即表值参数,表值参数可以发送更多的SQL Server数据。下面的示例展示了如何使用表值参数。
例2-4 使用表值参数
USE AdventureWorks; GO /* 创建一个表数据类型 */ CREATE TYPE LocationTableType AS TABLE ( LocationName VARCHAR(50) , CostRate INT ); GO /* 创建一个过程,用于接收表值参数中的数据*/ 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 @LocationTVP AS LocationTableType; /* 增加数据到表变量中 */ INSERT INTO @LocationTVP (LocationName, CostRate) SELECT [Name], 0.00 FROM [AdventureWorks].[Person].[StateProvince]; EXEC usp InsertProductionLocation @LocationTVP; GO
2.4.7 MERGE语句
SQL Server 2008包含用于合并两个行集(rowset)数据的新句法。一个源数据表对另一个数据表进行确定性的插入、更新和删除这样复杂的操作,运用新的MERGE语句,开发者用一条命令就可以完成。
对两个表进行信息同步时,有三步操作要进行。首先要处理任何需要插入目标数据表的新行;其次是处理需要更新的已存在的行;最后要删除不再使用的旧行。这个过程中需要维护大量重复的逻辑,并可能导致某些细微的错误。
这个新增的T-SQL语句在一个基于源数据连接结果集的目标表上执行 INSERT、UPDATE和DELETE操作。该语法允许你将一个数据源连接到目标表或视图上,然后在连接后的结果集上执行多种操作。
下面来看一个示例,如何在一条SQL语句中使用MERGE在一张表上执行UPDATE和DELETE操作。
例2-5 使用MERGE在一张表上执行更新和删除操作
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等更加灵活和强大。这个新句法的一个美妙之处是它在处理更新时的确定性。在使用标准的UPDATE句法和联合时,可能有超过一个源行跟目标行匹配。在这种情况下,无法预料更新操作会采用哪个源行的数据。而当使用MERGE句法时,如果存在多处匹配,它会抛出一个错误。这就提醒了开发者,要达到预想的目标,当前的联合条件还不够明确。