FROM (Transact-SQL)
指定在 SQL Server 2012 的 DELETE、SELECT 和 UPDATE 语句中使用的表、视图、派生表和联接表。 在 SELECT 语句中,FROM 子句是必需的,除非选择列表只包含常量、变量和算术表达式(没有列名)。
语法
[ FROM { <table_source> } [ ,...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>
| @variable [ [ AS ] table_alias ]
| @variable.function_call ( expression [ ,...n ] ) [ [ AS ] table_alias ] [ (column_alias [ ,...n ] ) ]
}
<tablesample_clause> ::=
TABLESAMPLE [SYSTEM] ( sample_number [ PERCENT | ROWS ] )
[ REPEATABLE ( repeat_seed ) ]
<joined_table> ::=
{
<table_source> <join_type> <table_source> ON <search_condition>
| <table_source> CROSS JOIN <table_source>
| left_table_source { CROSS | OUTER } APPLY right_table_source
| [ ( ] <joined_table> [ ) ]
}
<join_type> ::=
[ { INNER | { { LEFT | RIGHT | FULL } [ OUTER ] } } [ <join_hint> ] ]
JOIN
<pivoted_table> ::=
table_source PIVOT <pivot_clause> [ AS ] table_alias
<pivot_clause> ::=
( aggregate_function ( value_column [ [ , ]...n ])
FOR pivot_column
IN ( <column_list> )
)
<unpivoted_table> ::=
table_source UNPIVOT <unpivot_clause> [ AS ] table_alias
<unpivot_clause> ::=
( value_column FOR pivot_column IN ( <column_list> ) )
<column_list> ::=
column_name [ ,...n ]
参数
<table_source>
指定要在 Transact-SQL 语句中使用的表、视图、表变量或派生表源(有无别名均可)。 虽然语句中可用的表源个数的限值根据可用内存和查询中其他表达式的复杂性而有所不同,但一个语句中最多可使用 256 个表源。 单个查询可能不支持最多有 256 个表源。注意 如果查询中引用了许多表,查询性能会受到影响。 编译和优化时间也受到其他因素的影响。 这些因素包括:每个 <table_source> 是否有索引和索引视图,以及 SELECT 语句中 <select_list> 的大小。
表源在 FROM 关键字后的顺序不影响返回的结果集。 如果 FROM 子句中出现重复的名称,SQL Server 会返回错误。
table_or_view_name
表或视图的名称。如果表或视图存在于 SQL Server 的同一实例的另一个数据库中,请按照 database.schema.object_name 形式使用完全限定名称。
如果表或视图不在 SQL Serverl 的实例中,请按照 linked_server.catalog.schema.object 的形式使用由四个部分组成的名称。 有关详细信息,请参阅 sp_addlinkedserver (Transact-SQL)。 如果由四个部分组成的名称的服务器部分使用的是 OPENDATASOURCE 函数,则该名称也可用于指定远程表源。 如果指定 OPENDATASOURCE,则 database_name 和 schema_name 可能不适用于所有数据源,并且受到访问远程对象的 OLE DB 访问接口的性能的限制。
[AS] table_alias
table_source 的别名,别名可带来使用上的方便,也可用于区分自联接或子查询中的表或视图。 别名往往是一个缩短了的表名,用于在联接中引用表的特定列。 如果联接中的多个表中存在相同的列名,SQL Server 要求使用表名、视图名或别名来限定列名。 如果定义了别名,则不能使用表名。如果使用派生表、行集或表值函数或者运算符子句(如 PIVOT 或 UNPIVOT),则在子句结尾处必需的 table_alias 是所有返回列(包括分组列)的关联表名。
WITH (<table_hint> )
指定查询优化器对此表和此语句使用优化或锁定策略。 有关详细信息,请参阅表提示 (Transact-SQL)。rowset_function
指定其中一个行集函数(如 OPENROWSET),该函数返回可用于替代表引用的对象。 有关行集函数的列表的详细信息,请参阅行集函数 (Transact-SQL)。使用 OPENROWSET 和 OPENQUERY 函数指定远程对象依赖于访问该对象的 OLE DB 访问接口的性能。
bulk_column_alias
代替结果集内列名的可选别名。 只允许在使用 OPENROWSET 函数和 BULK 选项的 SELECT 语句中使用列别名。 使用 bulk_column_alias 时,为每个表列指定别名,顺序与这些列在文件中的顺序相同。注意 此别名覆盖 XML 格式化文件的 COLUMN 元素中的 NAME 属性(如果有该属性)。
user_defined_function
指定表值函数。OPENXML <openxml_clause>
通过 XML 文档提供行集视图。 有关详细信息,请参阅 OPENXML (Transact-SQL)。derived_table
从数据库中检索行的子查询。 derived_table 用作外部查询的输入。derived_table 可以使用 Transact-SQL 表值构造函数功能来指定多个行。 例如,SELECT * FROM (VALUES (1, 2), (3, 4), (5, 6), (7, 8), (9, 10) ) AS MyTable(a, b);。 有关详细信息,请参阅表值构造函数 (Transact-SQL)。
column_alias
代替派生表的结果集内列名的可选别名。 在选择列表中的每个列包括一个列别名,并将整个列别名列表用圆括号括起来。<tablesample_clause>
指定返回来自表的数据样本。 该样本可以是近似的。 此子句可对 SELECT、UPDATE 或 DELETE 语句中的任何主表或联接表使用。 不能对视图指定 TABLESAMPLE。注意 对升级到 SQL Server 的数据库使用 TABLESAMPLE 时,数据库的兼容级别必须设置为 110 或更高,在递归公用表表达式 (CTE) 查询中不允许 PIVOT。 有关详细信息,请参阅 ALTER DATABASE 兼容级别 (Transact-SQL)。
SYSTEM
ISO 标准指定的依赖于实现的抽样方法。 在 SQL Server 中,这是唯一可用的抽样方法,并且是默认应用的方法。 SYSTEM 应用基于页的抽样方法,即从表中选择一组随机页作为样本,这些页上的所有行作为样本子集返回。sample_number
表示行的百分比或行数的精确或近似的常量数值表达式。 使用 PERCENT 指定时,sample_number 被隐式转换为 float 值;否则,它被转换为 bigint。 PERCENT 是默认设置。PERCENT
指定应该从表中检索表行的 sample_number 百分比。 指定 PERCENT 时,SQL Server 返回指定的百分比的近似值。 指定 PERCENT 时,sample_number 表达式的值必须是 0 到 100 之间的值。ROWS
指定将检索的行的近似 sample_number。 指定 ROWS 时,SQL Server 返回指定的行数的近似值。 指定 ROWS 时,sample_number 表达式的值必须是大于零的整数值。REPEATABLE
指示可以再次返回选定的样本。 使用同一个 repeat_seed 值指定时,只要对表中任何行尚未进行更改,SQL Server 就会返回相同的行集。 使用其他 repeat_seed 值指定时,SQL Server 很可能将返回表中行的某些不同样本。 对表的以下操作可视为更改:插入、更新、删除、索引重新生成或碎片整理以及数据库还原或附加。repeat_seed
SQL Server 用于生成随机数的常量整数表达式。 repeat_seed 的数据类型为 bigint。 如果未指定 repeat_seed,SQL Server 将随机分配值。 对于特定的 repeat_seed 值,如果尚未对表应用任何更改,抽样结果始终相同。 repeat_seed 表达式的值必须是大于零的整数。<joined_table>
由两个或更多表的积构成的结果集。 对于多个联接,请使用圆括号来更改联接的自然顺序。<join_type>
指定联接操作的类型。INNER
指定返回所有匹配的行对。 放弃两个表中不匹配的行。 如果未指定任何联接类型,此设置为默认设置。FULL [ OUTER ]
指定在结果集中包括左表或右表中不满足联接条件的行,并将对应于另一个表的输出列设为 NULL。 这是对通常由 INNER JOIN 返回的所有行的补充。LEFT [ OUTER ]
指定在结果集中包括左表中所有不满足联接条件的行,除了由内部联接返回所有的行之外,还将另外一个表的输出列设置为 NULL。RIGHT [OUTER]
指定在结果集中包括右表中所有不满足联接条件的行,除了由内部联接返回所有的行之外,还将与另外一个表对应的输出列设置为 NULL。<join_hint>
指定 SQL Server 查询优化器为在查询的 FROM 子句中指定的每个联接使用一个联接提示或执行算法。 有关详细信息,请参阅联接提示 (Transact-SQL)。JOIN
指示指定的联接操作应在指定的表源或视图之间执行。ON <search_condition>
指定联接所基于的条件。 虽然常常使用列运算符和比较运算符,但该条件可指定任何谓词,例如:USE AdventureWorks2012 ; GO SELECT p.ProductID, v.BusinessEntityID FROM Production.Product AS p JOIN Purchasing.ProductVendor AS v ON (p.ProductID = v.ProductID);
当该条件指定列时,列不必具有相同的名称或数据类型;但是,如果数据类型不相同,则这些列要么必须相互兼容,要么是 SQL Server 能够隐式转换的类型。 如果数据类型不能隐式转换,则在条件中必须使用 CONVERT 函数显式转换数据类型。
在 ON 子句中可能有仅涉及一个联接表的谓词。 这样的谓词也可能出现在查询中的 WHERE 子句中。 虽然这种谓词的放置对于 INNER 联接不会产生差别,但是在涉及 OUTER 联接时可能会导致不同的结果。 这是因为 ON 子句中的谓词在应用于联接之前先应用于表,而 WHERE 子句在语义上应用于联接结果。
有关搜索条件和谓词的详细信息,请参阅搜索条件 (Transact-SQL)。
CROSS JOIN
指定两个表的叉积。 返回相同的行,就好像在旧式的非 SQL-92 式联接中并没有指定 WHERE 子句。left_table_source{ CROSS | OUTER } APPLYright_table_source
指定针对 left_table_source 的每行,对 APPLY 运算符的 right_table_source 求值。 当 right_table_source 包含从 left_table_source 取列值作为其参数之一的表值函数时,此功能很有用。必须使用 APPLY 指定 CROSS 或 OUTER。 如果指定 CROSS,针对 right_table_source 的指定行对 left_table_source 求值,且返回了空的结果集,则不生成任何行。
如果指定 OUTER,则为 left_table_source 的每行生成一行,即使在针对该行对 right_table_source 求值且返回空的结果集时也是如此。
有关详细信息,请参见“备注”部分。
left_table_source
上一个参数中定义的一个表源。 有关详细信息,请参见“备注”部分。right_table_source
上一个参数中定义的一个表源。 有关详细信息,请参阅“备注”部分。table_source PIVOT <pivot_clause>
指定基于 pivot_column 透视 table_source。 table_source 是一个表或表表达式。 输出是包含 table_source 中 pivot_column 和 value_column 列之外的所有列的表。 table_source 中 pivot_column 和 value_column 列之外的列被称为透视运算符的分组列。PIVOT 对输入表执行分组列的分组操作,并为每个组返回一行。 此外,input_table 的 pivot_column 中显示的 column_list 中指定的每个值,输出中都对应一列。
有关详细信息,请参见后面的“备注”部分。
aggregate_function
接受一个或多个输入的系统聚合函数或用户定义的聚合函数。 聚合函数应该对 Null 值固定不变。 对 Null 值固定不变的聚合函数在求聚合值时不考虑组中的 Null 值。不允许使用 COUNT(*) 系统聚合函数。
value_column
PIVOT 运算符的值列。 与 UNPIVOT 一起使用时,value_column 不能是输入 table_source 中的现有列的名称。FOR pivot_column
PIVOT 运算符的透视列。 pivot_column 的数据类型必须可隐式或显式转换为 nvarchar()。 此列不能为 image 或 rowversion。使用 UNPIVOT 时,pivot_column 是从 table_source 中提取的输出列的名称。 table_source 中不能有该名称的现有列。
IN (column_list )
在 PIVOT 子句中,列出 pivot_column 中将成为输出表的列名的值。 该列表不能指定被透视的输入 table_source 中已存在的任何列名。在 UNPIVOT 子句中,列出 table_source 中将被提取到单个 pivot_column 中的列。
table_alias
输出表的别名。 必须指定 pivot_table_alias。UNPIVOT < unpivot_clause >
指定输入表从 column_list 中的多个列缩减为名为 pivot_column 的单个列。
注释
FROM 子句支持用于联接表和派生表的 SQL-92-SQL 语法。 SQL-92 语法提供 INNER、LEFT OUTER、RIGHT OUTER、FULL OUTER 和 CROSS 联接运算符。
视图、派生表和子查询中均支持 FROM 子句内的 UNION 和 JOIN。
自联接是与自身联接的表。 基于自联接的插入和更新操作遵循 FROM 子句中的顺序。
因为 SQL Server 会考虑来自提供列分布统计信息的链接服务器的分布及基数统计信息,所以,无需 REMOTE 联接提示来强制远程评估联接。 SQL Server 查询处理器将考虑远程统计信息,并确定远程联接策略是否适当。 REMOTE 联接提示对不提供列分发统计信息的提供程序非常有用。
使用 APPLY
APPLY 运算符的左操作数和右操作数都是表表达式。 这些操作数之间的主要区别是,right_table_source 可以使用表值函数,从 left_table_source 获取一个列作为函数的参数之一。 left_table_source 可以包括表值函数,但不能以来自 right_table_source 的列作为参数。
APPLY 运算符通过以下方式工作,以便为 FROM 子句生成表源:
对 left_table_source 的每行计算 right_table_source 的值来生成行集。
right_table_source 中的值依赖于 left_table_source。 right_table_source 可以按以下方式近似表示:TVF(left_table_source.row),其中,TVF 是表值函数。
通过执行 UNION ALL 操作,将计算 right_table_source 的值时为每行生成的结果集与 left_table_source 组合起来。
APPLY 运算符的结果生成的列的列表是来自 left_table_source(与来自 right_table_source 的列的列表相组合)的一组列。
使用 PIVOT 和 UNPIVOT
pivot_column 和 value_column 是 PIVOT 运算符使用的分组列。 PIVOT 遵循以下过程获得输出结果集:
对分组列的 input_table 执行 GROUP BY,为每个组生成一个输出行。
输出行中的分组列获得 input_table 中该组的对应列值。
通过执行以下操作,为每个输出行生成列列表中的列的值:
针对 pivot_column,对上一步在 GROUP BY 中生成的行另外进行分组。
对于 column_list 中的每个输出列,选择满足以下条件的子组:
pivot_column = CONVERT(<data type of pivot_column>, 'output_column')
针对此子组上的 aggregate_function 对 value_column 求值,其结果作为相应的 output_column 的值返回。 如果该子组为空,SQL Server 将为该 output_column 生成 Null 值。 如果聚合函数是 COUNT,且子组为空,则返回零 (0)。
权限
需要 DELETE、SELECT 或 UPDATE 语句的权限。
示例
A.使用简单 FROM 子句
下面的示例从 AdventureWorks2012 示例数据库中的 SalesTerritory 表中检索 TerritoryID 和 Name 列。
USE AdventureWorks2012 ;
GO
SELECT TerritoryID, Name
FROM Sales.SalesTerritory
ORDER BY TerritoryID ;
下面是结果集:
TerritoryID Name
----------- ------------------------------
1 Northwest
2 Northeast
3 Central
4 Southwest
5 Southeast
6 Canada
7 France
8 Germany
9 Australia
10 United Kingdom
(10 row(s) affected)
B.使用 TABLOCK 和 HOLDLOCK 优化器提示
下面的部分事务说明了如何在 Employee 上放置一个显式共享表锁,以及如何读取索引。 该锁将在整个事务中被持有。
USE AdventureWorks2012 ;
GO
BEGIN TRAN
SELECT COUNT(*)
FROM HumanResources.Employee WITH (TABLOCK, HOLDLOCK) ;
C.使用 SQL-92 CROSS JOIN 语法
下面的示例返回 Employee 和 Department 这两个表的叉积。 所返回的列表包含 BusinessEntityID 行和所有 Department 名称行的所有可能的组合。
USE AdventureWorks2012 ;
GO
SELECT e.BusinessEntityID, d.Name AS Department
FROM HumanResources.Employee AS e
CROSS JOIN HumanResources.Department AS d
ORDER BY e.BusinessEntityID, d.Name ;
D.使用 SQL-92 FULL OUTER JOIN 语法
下面的示例返回产品名称以及 SalesOrderDetail 表中任何对应的销售订单。 该示例还将返回在 Product 表中没有列出产品的任何销售订单,以及销售订单不同于在 Product 表中列出的销售订单的任何产品。
USE AdventureWorks2012 ;
GO
-- The OUTER keyword following the FULL keyword is optional.
SELECT p.Name, sod.SalesOrderID
FROM Production.Product AS p
FULL OUTER JOIN Sales.SalesOrderDetail AS sod
ON p.ProductID = sod.ProductID
WHERE p.ProductID IS NULL OR sod.ProductID IS NULL
ORDER BY p.Name ;
E.使用 SQL-92 LEFT OUTER JOIN 语法
下面的示例基于 ProductID 联接两个表,并保留左表中不匹配的行。 Product 表与每个表中的 ProductID 列上的 SalesOrderDetail 表相匹配。 所有产品,无论是否已订购,都将在结果集中显示。
USE AdventureWorks2012 ;
GO
SELECT p.Name, sod.SalesOrderID
FROM Production.Product AS p
LEFT OUTER JOIN Sales.SalesOrderDetail AS sod
ON p.ProductID = sod.ProductID
ORDER BY p.Name ;
F.使用 SQL-92 INNER JOIN 语法
下面的示例返回所有产品名称和销售订单 ID。
USE AdventureWorks2012 ;
GO
-- By default, SQL Server performs an INNER JOIN if only the JOIN
-- keyword is specified.
SELECT p.Name, sod.SalesOrderID
FROM Production.Product AS p
INNER JOIN Sales.SalesOrderDetail AS sod
ON p.ProductID = sod.ProductID
ORDER BY p.Name ;
G.使用 SQL-92 RIGHT OUTER JOIN 语法
下面的示例基于 TerritoryID 联接两个表,并保留右表中不匹配的行。 SalesTerritory 表与每个表中的 TerritoryID 列上的 SalesPerson 表相匹配。 不论是否分配了区域,所有销售人员均在结果集中显示。
USE AdventureWorks2012 ;
GO
SELECT st.Name AS Territory, sp.BusinessEntityID
FROM Sales.SalesTerritory AS st
RIGHT OUTER JOIN Sales.SalesPerson AS sp
ON st.TerritoryID = sp.TerritoryID ;
H.使用 HASH 和 MERGE 联接提示
下面的示例在 Product、ProductVendor 和 Vendor 表之间执行三表联接,生成产品及其供应商的列表。 查询优化器使用 MERGE 联接来联接 Product 和 ProductVendor(p 和 pv)。 然后,Product 和 ProductVendor MERGE 联接(p 和 pv)的结果被 HASH 联接到 Vendor 表,生成(p 和 pv)和 v。
重要提示 |
---|
指定了联接提示后,要执行 INNER JOIN 时,INNER 关键字不再为可选,而必须显式说明。 |
USE AdventureWorks2012 ;
GO
SELECT p.Name AS ProductName, v.Name AS VendorName
FROM Production.Product AS p
INNER MERGE JOIN Purchasing.ProductVendor AS pv
ON p.ProductID = pv.ProductID
INNER HASH JOIN Purchasing.Vendor AS v
ON pv.BusinessEntityID = v.BusinessEntityID
ORDER BY p.Name, v.Name ;
I.使用派生表
下面的示例使用派生表(FROM 子句后的 SELECT 语句)返回所有员工的名字和姓氏及其居住的城市。
USE AdventureWorks2012 ;
GO
SELECT RTRIM(p.FirstName) + ' ' + LTRIM(p.LastName) AS Name, d.City
FROM Person.Person AS p
INNER JOIN HumanResources.Employee e ON p.BusinessEntityID = e.BusinessEntityID
INNER JOIN
(SELECT bea.BusinessEntityID, a.City
FROM Person.Address AS a
INNER JOIN Person.BusinessEntityAddress AS bea
ON a.AddressID = bea.AddressID) AS d
ON p.BusinessEntityID = d.BusinessEntityID
ORDER BY p.LastName, p.FirstName;
J.使用 TABLESAMPLE 从表中的行样本中读取数据
下面的示例在 FROM 子句中使用 TABLESAMPLE,大约返回 Customer 表中所有行的 10%。
USE AdventureWorks2012 ;
GO
SELECT *
FROM Sales.Customer TABLESAMPLE SYSTEM (10 PERCENT) ;
K.使用 APPLY
下面的示例假定数据库中存在具有如下架构的以下表:
Departments: DeptID, DivisionID, DeptName, DeptMgrID
EmpMgr: MgrID, EmpID
Employees: EmpID, EmpLastName, EmpFirstName, EmpSalary
还有一个表值函数 (GetReports(MgrID)) 可以返回指定的 MgrID 直接或间接领导的所有员工的列表(EmpID、EmpLastName、EmpSalary)。
该示例使用 APPLY 返回所有部门和部门中的所有员工。 如果某个部门没有任何员工,则将不返回该部门的任何行。
SELECT DeptID, DeptName, DeptMgrID, EmpID, EmpLastName, EmpSalary
FROM Departments d CROSS APPLY dbo.GetReports(d.DeptMgrID) ;
如果您希望查询为那些没有员工的部门生成行(这将为 EmpID、EmpLastName 和 EmpSalary 列生成 Null 值),请改用 OUTER APPLY。
SELECT DeptID, DeptName, DeptMgrID, EmpID, EmpLastName, EmpSalary
FROM Departments d OUTER APPLY dbo.GetReports(d.DeptMgrID) ;
L.使用 PIVOT 和 UNPIVOT
下面的示例返回按员工 ID(164、198、223、231 和 233)下达并按供应商 ID 分类的采购订单的数量。
USE AdventureWorks2012;
GO
SELECT VendorID, [250] AS Emp1, [251] AS Emp2, [256] AS Emp3, [257] AS Emp4, [260] AS Emp5
FROM
(SELECT PurchaseOrderID, EmployeeID, VendorID
FROM Purchasing.PurchaseOrderHeader) AS p
PIVOT
(
COUNT (PurchaseOrderID)
FOR EmployeeID IN
( [250], [251], [256], [257], [260] )
) AS pvt
ORDER BY VendorID;
以下为部分结果集:
VendorID Emp1 Emp2 Emp3 Emp4 Emp5
----------------------------------------------------------------
1 4 3 5 4 4
2 4 1 5 5 5
3 4 3 5 4 4
4 4 2 5 5 4
5 5 1 5 5 5
若要对表进行逆透视,请假定在上一个示例中生成的结果集是作为 pvt 存储的。 该查询如下所示。
--Create the table and insert values as portrayed in the previous example.
CREATE TABLE dbo.pvt (VendorID int, Emp1 int, Emp2 int,
Emp3 int, Emp4 int, Emp5 int);
GO
INSERT INTO dbo.pvt VALUES
(1,4,3,5,4,4)
,(2,4,1,5,5,5)
,(3,4,3,5,4,4)
,(4,4,2,5,5,4)
,(5,5,1,5,5,5);
GO
--Unpivot the table.
SELECT VendorID, Employee, Orders
FROM
(SELECT VendorID, Emp1, Emp2, Emp3, Emp4, Emp5
FROM dbo.pvt) AS p
UNPIVOT
(Orders FOR Employee IN
(Emp1, Emp2, Emp3, Emp4, Emp5)
)AS unpvt
GO
以下为部分结果集:
VendorID Employee Orders
------------------------------
1 Emp1 4
1 Emp2 3
1 Emp3 5
1 Emp4 4
1 Emp5 4
2 Emp1 4
2 Emp2 1
2 Emp3 5
2 Emp4 5
2 Emp5 5
M.使用 CROSS APPLY
以下示例将检索驻留在计划缓存中的所有查询计划的快照,方法是通过查询 sys.dm_exec_cached_plans 动态管理视图来检索缓存中所有查询计划的计划句柄。 然后,指定 CROSS APPLY 运算符以将计划句柄传递给 sys.dm_exec_query_plan。 当前在计划缓存中的每个计划的 XML 显示计划输出位于返回的表的 query_plan 列中。
USE master;
GO
SELECT dbid, object_id, query_plan
FROM sys.dm_exec_cached_plans AS cp
CROSS APPLY sys.dm_exec_query_plan(cp.plan_handle);
GO