虽然 SELECT 语句的完整语法较复杂,但是其主要的子句可归纳如下:
SELECT select_list
[INTO new_table_name]
FROM table_list
[WHERE search_conditions]
[GROUP BY group_by_list]
[HAVING search_conditions]
[ORDER BY order_list [ASC | DESC] ]
select_list
描述结果集的列。它是一个逗号分隔的表达式列表。每个表达式同时定义格式(数据类型和大小)和结果集列的数据来源。每个选择列表表达式通常是对从中获取数据的源表或视图的列的引用,但也可能是其它表达式,例如常量或 Transact-SQL 函数。在选择列表中使用 * 表达式指定返回源表中的所有列。
INTO new_table_name
指定使用结果集来创建新表。new_table_name 指定新表的名称。
FROM table_list
包含从中检索到结果集数据的表的列表。这些来源可能包括:
FROM 子句还可包含联接说明,该说明定义了 SQL Server 用来在表之间进行导航的特定路径。
FROM 子句还用在 DELETE 和 UPDATE 语句中以定义要修改的表。
WHERE search_conditions
WHERE 子句是一个筛选,它定义了源表中的行要满足 SELECT 语句的要求所必须达到的条件。只有符合条件的行才向结果集提供数据。不符合条件的行中的数据不会被使用。
WHERE 子句还用在 DELETE 和 UPDATE 语句中以定义目标表中要修改的行。
GROUP BY group_by_list
GROUP BY 子句根据 group_by_list 列中的值将结果集分成组。例如,Northwind Orders 表在 ShipVia 中有三个值。GROUP BY ShipVia 子句将结果集分成三组,每组对应于 ShipVia 的一个值。
HAVING search_conditions
HAVING 子句是应用于结果集的附加筛选。逻辑上讲,HAVING 子句从中间结果集对行进行筛选,这些中间结果集是用 SELECT 语句中的 FROM、WHERE 或 GROUP BY 子句创建的。HAVING 子句通常与 GROUP BY 子句一起使用,尽管 HAVING 子句前面不必有 GROUP BY 子句。
ORDER BY order_list [ ASC | DESC ]
ORDER BY 子句定义结果集中的行排列的顺序。order_list 指定组成排序列表的结果集的列。ASC 和 DESC 关键字用于指定行是按升序还是按降序排序。
ORDER BY 之所以重要,是因为关系理论规定除非已经指定 ORDER BY,否则不能假设结果集中的行带有任何序列。如果结果集行的顺序对于 SELECT 语句来说很重要,那么在该语句中就必须使用 ORDER BY 子句。
必须按照正确的顺序指定 SELECT 语句中的子句。
对数据库对象的每个引用都不得引起歧义。下列情况可能会导致多义性:
SELECT * FROM User1.TableX
SELECT * FROM Northwind.dbo.Shippers
SELECT DISTINCT Customers.CustomerID, Customers.CompanyName FROM Customers JOIN Orders ON ( Customers.CustomerID = Orders.CustomerID) WHERE Orders.ShippedDate > 'May 1 1998'
当必须完全限定表和视图名称本身时,上述语法会变得很烦琐。通过在 FROM 子句中使用 AS 关键字为表指派一个相关名称(也称为范围变量或别名)即可解决此问题。只能在 FROM 子句中定义完全合法的表或视图名称。然后所有其它表或视图引用都可使用此相关名称。在前一个示例中应用相关名称并且完全限定表,会有如下的 SELECT 语句:
SELECT DISTINCT Cst.CustomerID, Cst.CompanyName FROM Northwind.dbo.Customers AS Cst JOIN Northwind.dbo.Orders AS Ord ON ( Cst.CustomerID = Ord.CustomerID) WHERE Ord.ShippedDate > 'May 1 1998'使用选择列表
选择列表可定义 SELECT 语句的结果集中的列。选择列表是以逗号分隔的一系列表达式。每个表达式定义结果集中的一列。结果集中列的排列顺序与选择列表中表达式的排列顺序相同。
结果集列的这些特性由选择列表中的下列表达式定义:
选择列表还可包含控制结果集的最终格式的关键字:
DISTINCT 关键字可从结果集中除去重复的行。例如,在 Northwind Orders 表中有许多行的 ShipCity 值是相同的。若要获得已删除重复内容的 ShipCity 值列表,请用如下语句:
SELECT DISTINCT ShipCity, ShipRegion FROM Orders ORDER BY ShipCity
TOP 关键字指定返回结果集的前 n 行。如果指定了 ORDER BY,行将在结果集排序之后选定。除非指定了 PERCENT 关键字,否则 n 即为返回的行数。PERCENT 指定 n 为结果集中返回的行的百分比。例如,SELECT 语句从 Orders 表中按照字母顺序返回前 10 个城市:
SELECT DISTINCT TOP 10 ShipCity, ShipRegion FROM Orders ORDER BY ShipCity
选择列表中的项目可包括:
如下示例显示了选择列表中可能包含的许多项目:
SELECT FirstName + ' ' + LastName AS "Employee Name", IDENTITYCOL AS "Employee ID", HomePhone, Region, 10 AS Constant FROM Northwind.dbo.Employees ORDER BY LastName, FirstName ASC选择所有列
在 SELECT 语句中,星号 (*) 具有特殊的意义:
USE Northwind GO SELECT * FROM Shippers ORDER BY CompanyName GO
USE Northwind GO SELECT Orders.OrderID, Shippers.* FROM Shippers JOIN Orders ON (Shippers.ShipperID = Orders.ShipVia) ORDER BY Orders.OrderID GO
当使用 * 时,结果集中的列的顺序与 CREATE TABLE、ALTER TABLE 或 CREATE VIEW 语句中所指定的顺序相同。
由于 SELECT * 会查找当前表中的所有列,因此每次执行 SELECT * 语句时,表结构的更改(添加、删除或重命名列)都会自动反映出来。
如果在一个与结果集中的列数具有逻辑相关性的应用程序或脚本中使用 SELECT,最好在选择列表中指定所有列而不是指定一个星号。如果稍后在 SELECT 语句所引用的表或视图中添加了列,那么,当单独列出列时,应用程序将不会受更改的影响。如果指定了 *,则新的列成为结果集的一部分后可能影响应用程序或脚本的逻辑。
如下示例首先检索 publishers 表中的所有列,然后按照 publishers 表最初创建时所定义的顺序显示这些列:
USE Northwind GO SELECT * FROM [Order Details] ORDER BY OrderID ASC GO
若要获得完全相同的结果,需要在 SELECT 语句之后按顺序显式列出表中所有列名:
USE Northwind GO SELECT OrderID, ProductID, UnitPrice, Quantity, Discount FROM [Order Details] ORDER BY OrderID ASC GO
说明 若要查找表的列名,则可使用 sp_help、SELECT column_name FROM INFORMATION_SCHEMA.
选择特定列
若要选择表中的特定列,则需在选择列表中明确地列出每一列。例如,若要仅列出作者的名字和他们的电话号码,可使用:
SELECT FirstName, HomePhone FROM Northwind.dbo.Employees ORDER BY FirstName ASC在选择列表中,对列的指定还可包括指定别名(例如,proj_sales AS "Projected Sales")或其它表达式,例如 price = price * 1.15 或 SUM(SalesAmount)。
常量通常不作为单独的列在结果集中指定。对于应用程序本身而言,与要求服务器将常量值合并到跨网络返回的每一个结果集的行中相比,在显示结果时将常量值内置于结果中更为有效。
此常规规则的例外情况包括:
当字符列串联起来时,为了保证正确的格式和可读性,需要在其中包含字符串常量。如下示例将 LastName 和 FirstName 列合并成一列。在合并后的新列中,字符串 ', ' 将名称的两个部分分开,如下所示:
SELECT LastName + ', ' + FirstName AS EmployeeName FROM Northwind.dbo.Employees ORDER BY LastName, FirstName ASC查询结果集中的常量
常量通常不作为单独的列在结果集中指定。对于应用程序本身而言,与要求服务器将常量值合并到跨网络返回的每一个结果集的行中相比,在显示结果时将常量值内置于结果中更为有效。
此常规规则的例外情况包括:
当字符列串联起来时,为了保证正确的格式和可读性,需要在其中包含字符串常量。如下示例将 LastName 和 FirstName 列合并成一列。在合并后的新列中,字符串 ', ' 将名称的两个部分分开,如下所示:
SELECT LastName + ', ' + FirstName AS EmployeeName FROM Northwind.dbo.Employees ORDER BY LastName, FirstName ASC选择列表中的计算值
选择列表可包含通过对一个或多个简单表达式应用运算符而创建的表达式。这使结果集中得以包含基表中不存在,但是由存储在基表中的值计算而来的值。这些结果集列被称为导出列,并且包括:
SELECT ROUND( (UnitPrice * .9), 2) AS DiscountPrice FROM Products WHERE ProductID = 58
SELECT ( CAST(ProductID AS VARCHAR(10)) + ': ' + ProductName ) AS ProductIDName FROM Products
SELECT ProductID, ProductName, CASE CategoryID WHEN 1 THEN ROUND( (UnitPrice * .6), 2) WHEN 2 THEN ROUND( (UnitPrice * .7), 2) WHEN 3 THEN ROUND( (UnitPrice * .8), 2) ELSE ROUND( (UnitPrice * .9), 2) END AS DiscountPrice FROM Products
SELECT Prd.ProductID, Prd.ProductName, ( SELECT SUM(OD.UnitPrice * OD.Quantity) FROM Northwind.dbo.[Order Details] AS OD WHERE OD.ProductID = Prd.ProductID ) AS SumOfSales FROM Northwind.dbo.Products AS Prd ORDER BY Prd.ProductID
通过在带有算术运算符、函数、转换或嵌套查询的选择列表中使用数字列或数字常量,对数据进行计算和运算。算术运算符使您得以对数字数据进行加、减、乘和除运算。
支持下列算术运算符。
符号 | 操作 |
---|---|
+ | 加 |
- | 减 |
/ | 除 |
* | 乘 |
% | 模 |
执行加、减、除和乘的算术运算符可用于任何数字列或表达式(int、smallint、tinyint、decimal、numeric、float、real、money 或 smallmoney)中。模运算符只能用于 int 列、smallint 列、tinyint 列或表达式中。
也可使用日期函数或常规加或减数学运算符对 datetime 和 smalldatetime 列进行算术运算。
可使用算术运算符执行涉及一个或多个列的计算。在算术表达式中常量的使用是可选的,如下所示:
SELECT ProductID, ProductName, UnitPrice * UnitsInStock AS InventoryValue FROM Northwind.dbo.Products指定结果集的列名
AS 子句可用来更改结果集列名或为导出列指定名称。
当结果集列由对表或视图中的列的引用进行定义时,结果集列的名称与所引用列的名称相同。AS 子句可用于为结果集列指定不同的名称或别名。这样可增加可读性。例如:
SELECT EmpSSN AS "Employee Social Security Number" FROM EmpTable在选择列表中,有些列进行了具体指定,而不是简单的对列的引用,这些列便是导出列。除非使用 AS 子句指定了一个名称,否则导出列没有名称。在如下示例中,如果移去 AS 子句,那么使用 DATEDIFF 函数指定的导出列就没有名称:
SELECT OrderID, DATEDIFF(dd, ShippedDate, GETDATE() ) AS DaysSinceShipped FROM Northwind.dbo.Orders WHERE ShippedDate IS NOT NULLAS 子句是在 SQL-92 标准中所定义的语法,用来为结果集列指派名称。下面是在 Microsoft® SQL Server™ 中首选的语法:
column_name AS column_alias
或
result_column_expression AS derived_column_name
Transact-SQL 为了兼容早期版本的 SQL Server,还支持下列语法:
column_alias = column_name
或
derived_column_name = result_column_expression
例如,上一个示例可用下列代码替换:
SELECT OrderID, DaysSinceShipped = DATEDIFF(dd, ShippedDate, GETDATE() ) FROM Northwind.dbo.Orders WHERE ShippedDate IS NOT NULL结果集列名的分隔
结果集列名是一个标识符。如果该名称是遵循标识符规则的常规标识符,那么就不需要分隔。如果该名称不遵循标识符规则,则必须使用方括号 ([]) 或双引号 (" ") 对其进行分隔。不论 QUOTED_IDENTIFIER 选项是如何设置的,都可使用双引号对结果集列名进行分隔。
说明 每个结果集的列名可最多使用 128 个字符。但是,DB-Library 应用程序(例如 isql 工具)在查询输出中最多将结果集列名截取为 30 个字符。SQL Server 6.5 或更低版本的 SQL Server ODBC 驱动程序也最多将结果集列名截取为 30 个字符。
如下示例在 publishers 表中根据 Book Publisher 列标题而不是默认的 pub_name 列标题检索出版商名称:
USE pubs SELECT pub_name AS "Book Publisher" FROM publishers ORDER BY pub_name ASC另外,Transact-SQL 的保留关键字可通过加引号而被用于列标题。例如,以下查询使用保留字 SUM 作为列标题:
USE pubs SELECT SUM(ytd_sales) AS "sum" FROM titlesTransact-SQL 还支持使用单引号 ('') 来分隔结果集列名。这可保持与 SQL Server 早期版本的兼容性,如下所示:
USE pubs SELECT SUM(ytd_sales) AS 'sum' FROM titles使用 DISTINCT 消除重复项
DISTINCT 关键字可从 SELECT 语句的结果中除去重复的行。如果没有指定 DISTINCT,那么将返回所有行,包括重复的行。例如,如果在 titleauthor 中选择所有作者 ID 时未使用 DISTINCT,那么将会返回下列行(其中包括一些重复的行):
USE pubs SELECT au_id FROM titleauthor下面是结果集:
au_id ----------- 172-32-1176 213-46-8915 213-46-8915 238-95-7766 267-41-2394 267-41-2394 274-80-9391 409-56-7008 427-17-2319 472-27-2349 486-29-1786 486-29-1786 648-92-1872 672-71-3249 712-45-1867 722-51-5454 724-80-9391 724-80-9391 756-30-7391 807-91-6654 846-92-7186 899-46-2035 899-46-2035 998-72-3567 998-72-3567 (25 row(s) affected)而使用了 DISTINCT 后,就能够除去重复项,而只查看唯一的作者 ID:
USE pubs SELECT DISTINCT au_id FROM titleauthor下面是结果集:
au_id ----------- 172-32-1176 213-46-8915 238-95-7766 267-41-2394 274-80-9391 409-56-7008 427-17-2319 472-27-2349 486-29-1786 648-92-1872 672-71-3249 712-45-1867 722-51-5454 724-80-9391 756-30-7391 807-91-6654 846-92-7186 899-46-2035 998-72-3567 (19 row(s) affected)
重要 涉及 DISTINCT 的语句的输出取决于列的排序规则或应用 DISTINCT 的表达式。有关不同排序规则的效果的更多信息,请参见 SQL Server 排序规则基础知识。
对于 DISTINCT 关键字来说,各空值将被认为是相互重复的内容。当 SELECT 语句中包括 DISTINCT 时,不论遇到多少个空值,在结果中只返回一个 NULL。
说明 为了与 SQL-92 标准和其它的 Microsoft® SQL Server™ 版本兼容,ALL 关键字可以显式请求所有行。但是,由于 ALL 是默认的,所以无需指定它。
使用 TOP 和 PERCENT 限制结果集
TOP 子句限制返回到结果集中的行数。
TOP n [PERCENT]
n 指定返回的行数。如果未指定 PERCENT,n 就是返回的行数。如果指定了 PERCENT,n 就是返回的结果集行的百分比,如下所示:
TOP 120 /*Return the top 120 rows of the result set. */ TOP 15 PERCENT /* Return the top 15% of the result set. */.如果一个 SELECT 语句既包含 TOP 又包含 ORDER BY 子句,那么返回的行将会从排序后的结果集中选择。整个结果集按照指定的顺序建立并且返回排好序的结果集的前 n 行。
限制结果集大小的另一种方法是在执行一个语句之前执行 SET ROWCOUNT n 语句。SET ROWCOUNT 与 TOP 的不同之处在于:
在每一条要从表或视图中检索数据的 SELCET 语句中,都需要使用 FROM 子句。用 FROM 子句可以:
FROM 子句是用逗号分隔的表名、视图名和 JOIN 子句的列表。
Transact-SQL 具有扩展功能,可支持在 FROM 子句中指定除表或视图之外的其它对象。这些对象返回结果集,也就是 OLE DB 术语中所说的行集,该结果集构成了虚拟表。然后 SELECT 语句就像操作表一样操作这些结果集。
FROM 子句可以指定:
SELECT * FROM Shippers
SELECT Cst.CustomerID, Cst.CompanyName, Cst.ContactName, Ord.ShippedDate, Ord.Freight FROM Northwind.dbo.Orders AS Ord JOIN Northwind.dbo.Customers AS Cst ON (Cst.CustomerID = Ord.CustomerID)
SELECT ST.stor_id, ST.stor_name FROM stores AS ST, (SELECT stor_id, COUNT(DISTINCT title_id) AS title_count FROM sales GROUP BY stor_id ) AS SA WHERE ST.stor_id = SA.stor_id AND SA.title_count = (SELECT COUNT(*) FROM titles)
Microsoft® SQL Server™ 2000 分布式查询的基础是链接服务器、OPENROWSET 和 OPENQUERY。它们提供了在 Transact-SQL 语句中查询或修改任意 OLE DB 数据源中数据的能力。
不需要 FROM 子句的 SELECT 语句是那些不从数据库内的任何表中选择数据的 SELECT 语句。这些 SELECT 语句只从局部变量或不对列进行操作的 Transact-SQL 函数中选择数据,例如:
SELECT @MyIntVariable SELECT @@VERSION SELECT DB_ID('Northwind')使用表别名
SELECT 语句的可读性可通过为表指定别名来提高,别名也称为相关名称或范围变量。指派表的别名时,可以使用也可以不使用 AS 关键字:
在下例中,为 publishers 指派了别名 p。
USE pubs SELECT p.pub_id, p.pub_name FROM publishers AS p
如果为表指派了别名,那么在该 Transact-SQL 语句中对该表的所有显式引用都必须使用别名,而不能使用表名。例如,下列 SELECT 语句将产生语法错误,因为该语句在已指派别名的情况下又使用了表名:
SELECT Customers.CustomerID, /* Illegal reference to Customers. */ Cst.FirstName, Cst.LastName FROM Northwind.dbo.Customers AS Cst用 WHERE 和 HAVING 筛选行
SELECT 语句中的 WHERE 和 HAVING 子句控制用源表中的那些行来构造结果集。WHERE 和 HAVING 是筛选。这两个子句指定指定一系列搜索条件,只有那些满足搜索条件的行才用来构造结果集。我们称满足搜索条件的行符合参与行集的限定条件。例如,下列 SELECT 语句中的 WHERE 子句将限定只选择地区为华盛顿州 (WA) 的行:
SELECT CustomerID, CompanyName FROM Northwind.dbo.Customers WHERE Region = 'WA'HAVING 子句通常与 GROUP BY 子句结合使用,尽管指定该子句时也可以不带 GROUP BY。HAVING 子句指定在应用 WHERE 子句的筛选后要进一步应用的筛选。例如,下列 WHERE 子句仅限定以高于 $100 的单价销售产品的订单,而 HAVING 子句进一步将结果限制为只包括 100 件以上的订单:
SELECT OrdD1.OrderID AS OrderID, SUM(OrdD1.Quantity) AS "Units Sold", SUM(OrdD1.UnitPrice * OrdD1.Quantity) AS Revenue FROM [Order Details] AS OrdD1 WHERE OrdD1.OrderID in (SELECT DISTINCT OrdD2.OrderID FROM [Order Details] AS OrdD2 WHERE OrdD2.UnitPrice > $100) GROUP BY OrdD1.OrderID HAVING SUM(OrdD1.Quantity) > 100WHERE 和 HAVING 子句中的搜索条件或限定条件可包括:
SELECT ProductID, ProductName FROM Northwind.dbo.Products WHERE CategoryID = 2 ORDER BY ProductID
SELECT CategoryID, ProductID, ProductName FROM Northwind.dbo.Products WHERE CategoryID BETWEEN 2 and 4 ORDER BY CategoryID, ProductID
SELECT CategoryID, ProductID, ProductName FROM Northwind.dbo.Products WHERE CategoryID IN (1,4,5,7) ORDER BY CategoryID, ProductID
SELECT CategoryID, ProductID, ProductName FROM Northwind.dbo.Products WHERE ProductName LIKE 'Ch%' ORDER BY CategoryID, ProductID
说明 可用于 text 列的 WHERE 条件只有返回其它数据类型的函数(如 PATINDEX())或运算符(如 IS NULL、IS NOT NULL、LIKE 和 NOT LIKE)。
SELECT CompanyName, City, Region, Country FROM Northwind.dbo.Customers WHERE Region IS NOT NULL ORDER BY CompanyName
说明 比较空值时请谨慎从事。例如,指定 = NULL 与指定 IS NULL 是不同的。有关更多信息,请参见空值。
USE Northwind GO SELECT OrdD1.OrderID, OrdD1.ProductID FROM "Order Details" OrdD1 WHERE OrdD1.Quantity > ALL (SELECT OrdD2.Quantity FROM "Order Details" OrdD2 JOIN Products Prd ON OrdD2.ProductID = Prd.ProductID WHERE Prd.CategoryID = 1) GO
SELECT ProductID, ProductName FROM Northwind.dbo.Products WHERE UnitsInStock < ReorderLevel OR (SupplierID = 15 AND CategoryID = 4)
说明 当在 WHERE 子句中搜索 Unicode 字符串时,请在搜索字符串之前加字符 N,例如:
SELECT CompanyName, ContactName, Phone, Fax FROM Northwind.dbo.Customers WHERE CompanyName = N'Berglunds snabbköp'