第一章 SELECT
一、使用SELECT
1、使用SELECT
SELECT可从数据库中读取数据列,从一或多列数据表中读取一或多笔数据列或行。它的基本语法如下:
SELECT 逗号分割的数据行名称列表FROM 数据表名称 |
2、查询处理的逻辑顺序
T-SQL语法与其他程序语言较大的区别在于其执行的逻辑处理流程。大部分程序码执行流程都是依照程序码撰写的先后顺序执行,但在T-SQL的逻辑处理过程中,第一个处理的顺序为FROM字句,而SELECT栏位子句则是最后一个步骤,如下表所示。
(8)SELECT (9) [DISTINCT] (11) [Top n] 传回结果列表[INTO 新数据表名称] (1) FROM 数据表 (3) [INNER | LFT | RIGHT] JOIN 数据表 (2) ON <数据表JOIN的条件> (4) [WHERE <过滤条件>] (5) [GROUP BY <群组语法>] (6) [WITH {CUBE | ROLLUP} (7) [HAVING <过滤条件>] (10) ORDER BY <排序列表> [ASC | DESC]] |
T-SQL执行之初,通常会先产生虚拟的数据表,也就是由步骤(1)取得执行此查询语法所需的全部数据,然后再通过步骤(2)、(3)找出要参照的其他数据表,进而组成一个总的数据表。如此大的数据表并不是用户所需要的,一般在组成大数据表后,会再经过多个不同的步骤,例如,WHERE字句过滤所需的记录、GROUP BY字句群组过滤后的数据等,缩小要回传的数据量。若部分子句在查询语法中没有被指定,则对应的步骤会被省略。
SQL Server支持UNICODE联盟定义的Unicode2.0标准(也成为UCS 2)。Unicode2.0是经由联盟成员一致同意而制定的标准。这个标准把每个字符关联到一个整数(数值由0到65536)。
Unicode是将字码指标对应到字符的标准语法。由于Unicode主要设计为涵盖世界上所有语言的字符,所以不需要使用不同的字码页(Code Page)来处理不同的字符集。SQL Server 2005支持Unicode Standard 3.2版。
3、过滤数据(WHRE 子句)
使用WHERE子句查询时,应注意以下事项:
(1) 当数据行的数据类型为char、nchar、varchar、nvarchar、text、datetime、smalldatetime等时,请记得前后加上单引号
(2) 当使用SELECT子句查询数据时,应尽量避免在内使用万用字符(*),传回所有数据行。并利用WHERE子句进一步限制查询结果,以确保所得的数据是有用的数据,降低传送过多数据所造成的负荷。
(3) 可以使用单引号(’)或双引号(“)括住字符串,但在此建议使用单引号括住字符串。当SET QUOTED IDENTIFIER选项设成ON时,双引号表示的是物件,就不允许将字符串括在其中。
3.1 使用万用字符
LIKE关键字可查询符合指定模式(pattern)的字符串、日期或时间数值。通过规则运算符来包含可供比对的模式。模式包含了所要查询的字符/串,它可以包含四种万用字符的任意组合。
万用字符 |
意义 |
% |
任何具有零或多个字符的字符串 |
- |
任何单一字符 |
[] |
指定范围中的任何单一字符(例如[a-f]或集合[abcdef]) |
[^] |
不在指定范围中的任何单一字符(例如[^a-f]或集合[^abcdef]) |
使用时,请将万用字符与字符串括在单引号中,例如:
(1)LIKE ‘Mc%’:查询以字母Mc开头的所有字符串,如Mcsadfsad。
(2)LIKE ‘_hery’:查询以字符串hery结尾、并且长度为5个字母的所有字符串,例如ahery。
(3)LIKE ‘[M-Z]ing’:查询以字符串ing结尾,并以M到Z之间的任何单一字母开头的字符串,如Ring。
(4)LIKE ‘M[^C]%’:查询以字母M开头,但并未以字母C作为第二个字母的所有字符串,如Macsfdasf。
若万用字符没有与LIKE关键字搭配使用,则它们将被误解成常数,而非模式(pattern),也就说,它们只代表本身的数值。
3.2 使用逻辑运算符
逻辑运算符有AND、OR及NOT。AND与OR用在WHERE子句中连接查询条件,NOT则是代表与布尔运算相反的结果。
(1) AND:结合两个布尔运算符,并在两个运算符都是TRUE时,传回TRUE,当在陈述语句中使用一个以上的逻辑运算符时,会先评估AND运算符,可以使用小括号来变更运算的顺序。
(2) OR:结合两个条件。如果任一布尔运算符是TRUE,便是TRUE。当在陈述语句中使用一个以上的逻辑运算符时,OR运算符会在AND运算符之后评估。此外,也可以使用小括号来变更运算的顺序。
(3) NOT:反转任何其他布尔运算符的值。
当陈述语句中使用一个以上的逻辑运算符时,NOT会第一个计算,接下来是AND,最后才是OR。先处理算术及位运算符,接着才处理逻辑运算符。
3.3 取回未知的值
NULL值表示是未知的值。NULL值与空值或零值不同。两个NULL值永远不会相等,因为每个NULL值都是未知的,两个NULL值之间、或是一个NULL与其他任何值的比较,都会传回未知。NULL值通常代表未知的、不适用的,或之后将要加入的数据。
若要在查询中测试NULL值,请在WHERE子句中使用IS NULL或IS NOT NULL。若要直观地以=NULL或<>NULL来判断,可以更改连接设定ANSI_NULLS为OFF,否则与=NULL或<>NULL比较的结果为UNKNOWN,无法正确地判断。但建议使用默认的ANSI_NULLS为ON,并用IS运算符来判断,因为这是处理NULL的惯例。
4、集合数据与分组
在一般的情况下,集合函数只会传回一个计算之后的值。使用集合函数的优点是在server端计算统计,等到数据统计出来之后,SQL Server只将结果传回给使用者,而不传回整个细节的结果集。
集合函数 |
语法定义 |
使用时限制 |
MIN或MAX |
MIN([ALL|DISTINCT]运算式 MAX([ALL|DISTINCT]运算式 |
运算式不可以使用于bit数据类型 会忽略任何Null值,如果是字元数据行,MAX会在定序顺序中寻找最高值,而MIN反之。DISTINCT对MAX、MIN没意义,只适用于SQL-92相容性。 |
SUM或AVG |
AVG([ALL|DISTINCT]运算式 SUM([ALL|DISTINCT]运算式 |
只能使用在以下数据类型:Int,smallint,tinyint,decimal,numeric,float,real,money,smallmoney |
COUNT |
COUNT([ALL|DISTINCT]运算式 |
使用COUNT(*)这个函数时要特别小心如果栏位值含有NULL的影响。几乎可以使用在任何数据类型,包括text、ntext、image。 |
4.1 分组数据与HAVING指令
Group By 子句可将多个数据列结合成单一的数据列,并使用集合函数计算分组后的结果。当指定GROUP BY时,GROUP BY 清单应该包括 SELECT 子句栏位清单中,任何非经集合运算的数据行,否则,GROUP BY 运算式必须完全符合运取清单。
使用Group By子句时,必须注意以下几点:
(1)SQL Server 会针对每一群组的数据计算出一个统计值;(2)如果SELECT子句中含有GROUP BY子句以及WHERE子句,则WHERE子句一定要放在GROUP BY子句之前;(3)在GROUP BY子句之后所列出的栏位内最好不要含有NULL值,因为GROUP BY子句会将所有NULL值归纳在同一组内;(4)如果想要利用分组后,集合函数的计算值来过滤,必须使用GROUP BY子句,并搭配HAVING子句限制传回的数据结果。
当使用GROUP BY子句搭配集合函数来查询数据时,如果想要进一步限制查询后的结果,可以使用WHERE子句或HAVING子句。
例如:
select vDepCode from HREmployee group by vDepCode HAVING COUNT(*)>1
4.2 利用附加指令产生额外集合数据
当SELECT语法中使用GROUP BY子句分组数据时,可以搭配ROLLUP和CUBE运算符一起使用,以得到完整的统计信息。
4.2.1 使用GROUP BY指令与ROLLUP运算符
通常在GROUP BY子句中使用两个以上的栏位搭配集合函数运算时,可以利用ROLLUP运算符整理出进一步的统计信息。
在GROUP BY子句之后加上CUBE或ROLLUP运算符时,必须注意一下几点(1)SQL Server分组的规则为“由左至右”,分完组才会进行统计计算;(2)GROUP BY子句之后最多不能超过10行。
例如:
select vDepCode,vEmpCode,count(vEmpCode) as empNumber
from HREmployee
group by vDepCode,vEmpCode
with ROLLUP
4.2.2 使用GROUP BY指令与CUBE运算符
如果在GROUP BY子句中使用两个以上的栏位搭配集合函数运算,并且希望统计之后的结果包含所有群组可能的组合时,就可以利用CUBE运算符。
例如:
select vDepCode,vEmpCode,count(vEmpCode) as empNumber
from HREmployee
group by vDepCode,vEmpCode
with CUBE
4.2.3 使用GROUPING函数
可以使用GROUPING函数区别哪些值是由WITH CUBE或是WITH ROLLUP所产生出来,以判断由这两个指令所产生出来的新值,在使用GROUPING函数时,应注意(1)提供一个新栏位放置GROUPING函数;(2)回传1代表该栏位值是由WITH CUBE或是WITH ROLLUP所产生;(3)回传0代表明细数据。
例如:
select vDepCode,GROUPING(vDepCode),
vEmpCode,GROUPING(vEmpCode),
count(vEmpCode) as empNumber
from HREmployee
group by vDepCode,vEmpCode
with CUBE
或
select vDepCode,GROUPING(vDepCode),
vEmpCode,GROUPING(vEmpCode),
count(vEmpCode) as empNumber
from HREmployee
group by vDepCode,vEmpCode
with ROLLUP
4.3 取得排名或顺序的函数
SQL Server 2005新增了几个关于记录在数据集合中的顺序(ranking)的函数,如RANK、DENSE_RANK、ROW_NUMBER和NTILE等。
函数名称 |
说明 |
RANK |
在结果集中每一笔记录所在的排名位置,但排名可能不连贯,例如,若有两个第一名,则下一个名次直接跳至第三名。 |
DENSE_RANK |
功能与RANK相似,但代表排名的数值是连贯的。 |
ROW_NUMBER |
依据群组呈现每一笔记录在该群中出现的顺序位置。 |
NTILE |
依据指定的分群数量将结果集分割(partition),并记录在各群位置。 |
上述的四个函数语法格式相同,都要搭配OVER子句,以指定分割或排序记录的方式,OVER子句定义如下:
OVER([PARTITION BY <提供数值的描述方式>,…[n]] ORDER BY <栏位> [ASC | DESC][,…[n]]) |
PARTITION BY子句决定排序的记录要如何分组,而ORDER BY子句则决定每一组的记录要如何排序,若省略了PARTITION BY子句则视全部的记录为一组。
4.3.1 ROW_NUMBER
在传回的记录集合内为每一笔记录标上顺序编号(sequential integer)。
例如:
select ROW_NUMBER() OVER(PARTITION BY vDepCode ORDER BY iId) rowNumber,*
from HREmployee
ROW_NUMBER函数传回的是各笔数据记录在结果集内的顺序编号,并不是该记录在数据表内绝对位置的编号。利用ROW_NUMBER在数据分页方面很有用,例如
4.3.2 RANK
RANK函数和ROW_NUMBER功能类似,但对于ORDER BY指定的栏位重复值,赋予相同的排序值,并对下一个值跳过重复的数量。
例如:
select RANK() OVER(PARTITION BY vDepCode ORDER BY iId) dense_rank,
vDepCode,vEmpCode,vEmpName
from HREmployee
4.3.3 DENSE_RANK
DENSE_RANK与RANK函数相似,但排序是连续的,不会因为前一个名次有重复记录,而跳过相同记录笔数的名次。
例如:
select DENSE_RANK() OVER(PARTITION BY vDepCode ORDER BY iId) dense_rank,
vDepCode,vEmpCode,vEmpName
from HREmployee
4.3.4 NTILE(n)
将结果集的数据排序过后,依据所指定的数量分n组,并给予每组一个组的编号。分组的方式很简单,将结果集的总记录数除上n,若有余数m,则前m组都多增一笔记录,也就是并不非所有的组都有相同的记录,但多记录的群组最多只有一笔记录。
例如:
select NTILE(5) OVER(PARTITION BY vDepCode ORDER BY iId) ntile,
vDepCode,vEmpCode,vEmpName
from HREmployee
4.4 利用附加指令产生额外集合数据
PIVOT让一笔笔记录可以某个栏位的多个值转成多个栏的定义,并在行列交错的各数据格填入集合值,一般也称查询方式为Crosstab查询,也就是MS Office Access提供的TRANSFORM语法功能。在以往SQL Server 2000之前的版本中没有提供PIVOT关键字。
PIVOT语法格式:
SELECT <PIVOT 运算后形成的临时数据表栏位列表> FROM <来源数据表> PIVOT (集合函数(提供集合值的栏位) FOR Pivot 栏位 IN (栏位列表))数据表的别名 WHERE 条件运算 |
例如:
select * from HREmployee
PIVOT(COUNT(iId)
FOR iId
IN([1],[2],[3],[4],[5])
)a
相当于SQL Server 2000 以前版本中的,如下语句
select vEmpCode,vEmpName,vDepCode,bUpManager,tClass,tWork,vEmail,
COUNT(CASE WHEN iId=1 THEN iId END) as [1],
COUNT(CASE WHEN iId=2 THEN iId END) as [2],
COUNT(CASE WHEN iId=3 THEN iId END) as [3],
COUNT(CASE WHEN iId=4 THEN iId END) as [4],
COUNT(CASE WHEN iId=5 THEN iId END) as [5]
from HREmployee
group by vEmpCode,vEmpName,vDepCode,bUpManager,tClass,tWork,vEmail
PIVOT运算符是取之前SELECT语法中FROM子句所提供的临时数据表,若数据来源定义了连接,也就是FROM子句搭配JOIN语法,其JION子句会让该临时表有重复栏位的定义(最起码重复JOIN所用的两方数据表相同的栏位),此时会出现数据表栏位定义重复的错误,可通过CTE或子查询所形成的临时数据表来解决此问题。
例如:
WITH tmpCTE
AS
(
SELECT hd.vDepCode,hd.vDepName,he.vEmpCode,he.vEmpName
FROM HREmployee he
JOIN HRDepartment hd
ON he.vDepCode = hd.vDepCode
)
SELECT * FROM tmpCTE
PIVOT(COUNT(vDepCode)
FOR vDepCode
IN([1],[2],[3])
)a
或
SELECT * FROM
(
SELECT hd.vDepCode,hd.vDepName,he.vEmpCode,he.vEmpName
FROM HREmployee he
JOIN HRDepartment hd
ON he.vDepCode = hd.vDepCode
)tmpCTE
PIVOT(COUNT(vDepCode)
FOR vDepCode
IN([1],[2],[3])
)a
除了Pivot外,还有UnPivot语法将Pivot的结果转回成以数据列表现细节的方式,
例如:
select * from
(
select * from HREmployee
PIVOT(COUNT(vDepCode)
FOR iId
IN([1],[2],[3],[4],[5])
)a
)aa
UnPivot(vDepCode for iId IN([1],[2],[3],[4],[5]))
as bb
order by iId
5、关联多个数据表
SQL Server是关系型数据库系统。T-SQL提供了连接陈述式,可让数据表水平连接,水平连接的结果会包含数据表间所有的栏位;若要垂直合并数据表,则可以利用UNION、EXCEPT、INTERESECT指令。
5.1 内部连接(INNER JOIN)
T-SQL提供两种不同的内部连接语法,格式分别为:
――ANSI SQL:1992 提供的语法 FROM 数据表1 <连接类型> 数据表2 ON <连接条件> ――ANSI SQL:1989 提供的语法 FROM 数据表1,数据表2 WHERE <连接条件> |
SQL-92标准可指定多种连接类型,如内部连接(INNER JOIN)、外部连接(OUTER JOIN)或是交叉连接(CROSS JOIN),并使用ON关键字指定连接条件,连接条件使用比较运算符比较连接数据表内数据行的值,并将结果连接起来。
SQL-89连接语法是将要连接的数据表,通过逗号分割的方式连接在FROM子句后,连接条件则指定于WHERE子句中,且SQL-89不提供外部连接。
5.2 外部连接(OUTER JOIN)
外部连接主要是用在两个数据表不一定相同数据时。OUTER JOIN提供的连接辨认选项有:LEFT OUTER JOIN(相当于旧式的*=);RIGHT OUTER JOIN(相当于旧式的=*); FULL OUTER JOIN。
连接辨认选项(如LEFT JOIN的LEFT)可用来指定哪一个基底数据表的内容要完整传回。如果指定的辨认选项是LEFT,代表要传回左边基底数据的完整数据列,反之,RIGHT代表要传回右边基底数据的完整数据列。FULL则会传回两边基底数据表的所有列,然后在没有符合条件的栏位填入NULL值。当使用OUTER JOIN时,可省略OUTER关键字。
在SQL SERVER 2005中若要支持旧版的外连接,可将数据库改为向前相容,语法为
EXEC sp_dbcmptlevel 数据库名称,80 |
但将数据库改为向前相容后,会导致无法使用SQL SERVER 2005新增的功能,可以使用下面的语法格式取消向前相容
EXEC sp_dbcmptlevel 数据库名称,90 |
5.3 交叉连接(CROSS JOIN)
交叉连接会将多个数据列中,可能的情况全部产生出来,未包含WHERE子句的交叉连接将产生连接所牵涉到的笛卡儿乘积,其结果集的大小为第一个数据表的数据列数乘以第二个数据表的数据列数。
例如:
select * from HREmployee cross join HRDepartment 相当于 select * from HREmployee,HRDepartment |
5.4 连接演算法
当查询最佳化程序要决定连接的执行方式时,需要考虑以下信息。
(1)数据表彼此间连接最佳的先后关系;(2)在数据表两两连接时,找出哪个适合做内层数据表,哪个做外层数据表;(3)决定所要采用的连接演算法,如网状连接、合并连接还是聚凑连接
5.4.1 网状连接
如果一个连接输入相当小(例如少于10笔数据列),但另一个连接数据相当大,而且在连接数据行建有索引的话,网状连接是最快速的连接,因为它们需要的I/O以及比较最少。
例如:
select he.vDepCode,hd.vDepName,he.vEmpCode,he.vEmpName from HRDepartment hd join HREmployee he on hd.vDepCode = he.vDepCode where hd.vDepCode='D004' |
如果外部输入相当小,内部连接已预先建立索引,且数据记录相当大的话,网状连接会特别有效。在小型的连接中,也就是只影响一小部分数据记录的查询,索引网状连接比合并连接与聚凑连接要好得多,然而在大型查询中,网状连接多半不是最佳选择。
5.4.2 合并连接
如果两个连接输入都不小,而且依连接数据行排序得话,合并连接是最快速的连接。如果两个连接输入都相当大,而且两个输入的大小类似,先行排序再进行合并连接所提供的效率大致类似聚凑连接。然而,如果两个输入的大小差异极大的话,聚凑连接多半较快。
例如:
select he.vDepCode,hd.vDepName,he.vEmpCode,he.vEmpName from HRDepartment hd join HREmployee he on hd.vDepCode = he.vDepCode |
合并连接本身的演算法非常快,但如果数据需要先排序,可能整体的代价反而较高。但如果数据量大且可以从已有的索引取得排序过的数据,那么合并连接往往是最快速的连接算法,或是查询的SQL语法本身就要求有GROUP BY、ORDER BY、CUBE等,则查询语法整体本来就要做排序,因此可以重用排序的结果,此时合并连接也是不错的选择。
5.4.3 聚凑连接(HASH JOIN)
聚凑连接(HASH JOIN)通常可以有效地处理大型、未排序、无索引的输入。一般来说,查询最佳化程序会先考虑网状连接或合并连接,但若数据表没有合用的索引,或者前两项合并方式无法有效执行时,才会采用聚凑连接。与合并连接类似的是,只有当连接述词中至少有一个相等(WHERE)子句时,才能使用聚凑连接。聚凑连接会将两个来源数据表建立成两个输入:组件输入(build input)与探查输入(probe input)。
组件输入是符合条件但数据较少的数据表,用其栏位算出哈希表(hash table)放到记忆体中。探查输入是记录笔数较多的一方。
聚凑连接在作为复杂查询的中间结果方面很有用,因为:中间结果没有索引(除非明确地储存到硬盘,然后建立索引),而且通常产生时也不会适当地排序,供查询计划的下一步使用;查询最佳化工具只估计中间结果的大小。聚凑连接用于许多种集合比对操作:内部连接;左、右与完整外部连接;左、右半连接;交集;联合与差异。此外,聚凑连接的变化可用来移除重复和进行分组,这些修改方式只使用一个输入,兼做组建与探查角色。
5.5 将多个结果集合并起来
5.5.1 UNION [ALL] 运算符
UNION运算符可将两个以上的查询结果数据集合并为一个。
例如:
select vEmpCode,vEmpName,vDepCode,null vDepName from HREmployee UNION select null vEmpCode,null vEmpName,vDepCode,vDepName from HRDepartment |
若要列出重复的记录,则可改用UNION ALL指令,例如
select vEmpCode,vEmpName,vDepCode,null vDepName from HREmployee UNION ALL select null vEmpCode,null vEmpName,vDepCode,vDepName from HRDepartment |
由于判断两个以上的数据来源内的个别数据列是否重复,需要额外的计算比较,尤其当数据列较多时,这是相当消耗效率的操作。所以,若确定参与的两个数据来源不会有重复数据,或不在乎重复的数据,则为了效率,使用UNION ALL比UNION佳。
5.5.2 INTERSECT运算符
NTERSECT 运算符可用来比较数据集间的相同值,接着回传左右两个查询结果都有的资料列,产生的结果集会删除重复的数据列。例如,当某笔数据在TableA 出现 n 次,NTERSECT 运算后仅会列出1笔记录。
SELECT vEmpCode,vDepCode FROM HREmployee INTERSECT SELECT vEmpCode,vDepCode FROM HRDepartment 相当于 select vEmpCode,vDepCode from ( SELECT vEmpCode,vDepCode FROM HREmployee UNION ALL SELECT vEmpCode,vDepCode FROM HRDepartment )a GROUP BY vEmpCode,vDepCode HAVING COUNT(*) >1 |
5.5.3 EXCEPT
EXCEPT运算符会比较左右两边数据集的差异,然后以左边的数据集为主,返回所有的数据,但不包含左右两边相同的数据列。换句话说,EXCEPT运算符会从左侧查询中返回在右侧查询中找不到的任何个别值。另外,若左边数据集有两笔相同的记录时,仅会返回一笔记录。
例如:
SELECT vEmpCode,vDepCode FROM HREmployee EXCEPT SELECT vEmpCode,vDepCode FROM HRDepartment |
6、CTE
Common Table Expression(CTE)兼具视图(view)和派生数据表(derived table)的能力,可以称为临时的视图,或是在同一批子查询语法中可重复使用的派生数据表。
建立视图的语法
CREATE VIEW <视图名称>(栏位名称) AS <SQL 语法> 使用视图的语法: SELECT <栏位列表> FROM <视图名称> |
派生数据表就是利用子查询临时返回一个数据表结构,再以该结构当作外层查询语法的数据表来源,使用派生表的方式如下:
SELECT <逗号分割的栏位列表> FROM (<SQL 查询语法>) AS <派生数据表名称>(栏位列表) |
使用CTE的语法
WITH <CTE 名称>(栏位名称列表) AS ( <SQL 查询语法> ) SELECT <栏位名称> FROM <CTE 名称> --此处也可以搭配INSERT、UPDATE、DELETE等语法 | |
定义 |
说明 |
CTE名称 |
CTE的名称与数据库内其他物件的名称并不相关,它只存在当下执行的Context中,而优先权高过同名的其他数据库物件,所以若取道同名的物件,在当下查询中会遮盖掉原存在的物件。 |
栏位名称列表 |
栏位名称列表是选择的,定义下方查询语法返回的数据栏位名称,因此若有定义的话,其个数要与下方查询语法的栏位个数相同;若不定义,则直接取查询语法的数据集合栏位名称为返回数据的栏位名称。 |
SQL查询语法 |
一段SELECT语法,与建立视图(view)相同。 |
例如:
WITH CteTable AS ( SELECT hd.vDepCode,hd.vDepName,he.vEmpCode,he.vEmpName FROM HRDepartment hd LEFT JOIN HREmployee he on hd.vDepCode = he.vDepCode ) SELECT * FROM CteTable ORDER BY vDepCode |
若想要重复使用类似视图的定义,但又不希望该定义永久存在数据库定义中,且在单一语句查询中,需要重复使用视图,而又不希望因为以派生数据表定义的方式,在同一句查询语法中,需要重复定义、分析与执行派生数据表,则比较损伤效率,则可以考虑CTE。
通过下面的设定,返回执行时所消耗的CPU以及I/O的资源 SET STATISTICS IO ON SET STATISTICS TIME ON |
7、APPLY运算符
SQL SERVER 2005新增了APPLY运算符,让SELECT查询语法可与返回数据表的函数(Table-Valued Function,TVF)做进一步的结合。这在数据表含有XML列时,结合XML内容转换为新的数据表列较为方便。
APPLY运算符让符合查询的每一笔记录都呼叫一次TVF函数,并将结果与原数据表的记录内容一起展开。
CROSS APPLY和OUTER APPLY,两者的差异只在外部的数据表逐笔记录带入到TVF之后,若TVF并无符合的记录返回,则CROSS APPLY运算将不会呈现该笔记录,而OUTER APPLY依然展现外部数据表对应的记录,但TVF相关的栏位则以NULL呈现。
例如:
CREATE FUNCTION F_HREmployeeByDepCode(@vDepCode as varchar(20)) RETURNS TABLE AS RETURN SELECT vEmpCode,vEmpName,vDepCode FROM HREmployee WHERE vDepCode = @vDepCode GO
SELECT Fhre.*,hrd.vDepName FROM HRDepartment hrd OUTER APPLY F_HREmployeeByDepCode(vDepCode) AS Fhre WHERE vDepName = '市场部' |
SQL SERVER 2005除了透过APPLY整合用户自定义函数的结果外,也可以在子查询中引用自定义函数,并在内外查询间建立相关性,也就是以外部查询的栏位带入到内层查询中,这在SQL SERVER 2000中是不允许的。
例如:
SELECT * FROM HREmployee h WHERE (SELECT COUNT(*) FROM F_HREmployeeByDepCode(h.vDepCode))=15 |