子查询是嵌套在另一个查询中的普通 T-SQL 查询,在有一个 SELECT 语句作为另一个费查询的部分数据或条件的基础时,通过括号创建子查询。
子查询通常用于满足下列某个需求。
SELECT
或者:
SELECT
显然,确切的语法会有所变化,不仅因为需要替换选择列表和确切的表名称,而且因为在内部查询和/或外部查询中有一个多表连接。
SELECT DISTINCT soh.OrderDate, sod.ProductID
FROM Sales.SalesOrderHeader sod
JOIN Sales.SalesOrderDetail sod on soh.SalesOrderID = sod.SalesOrderID
WHERE OrderDate = (SELECT MIN(OrderDate) FROM Sales.SalesOrderHeader)
SELECT ProductID, Name
FROM Production.Product
WHERE ProductID IN (
SELECT ProductID FROM Sales.SpecialOfferProduct ):
)
尽管这种工作方式很好,但更好的方式是使用内部连接实现,而不是使用嵌套的 SELECT。例如,可以通过允许简单的连接来得到同于的结果。
SELECT DISTINCT pp.ProductID, Name
FROM Production.Product PP
JOIN Sales.SpecialOfferProduction ssop on pp.ProductID = ssop.ProductID;
由于性能方面的考虑,如果没有特别的理由使用嵌套的 SELECT 的话,则还应该使用连接方法作为默认解决方案。
SELECT Description
FROM Sales.SpecialOffer sso
WHERE sso.SpecialOfferID != 1
AND sso.SpecialOfferID NOT IN
(SELECT SpecialOfferID FROM Sales.SpecialOfferProduct);
上面的功能也可以用外连接实现
SELECT Description
FROM Sales.SpecialOfferProduct ssop
RIGHT OUTER JOIN Sales.SpecialOffer sso on sso.SpecialOfferID = ssop.SpecialOfferID
WHERE sso.SpecialOfferID != 1 AND sso.SpecialOfferID IS NULL;
USE AdventureWorks2008;
-- Get a list of customers and the date of their first order
SELECT soh.CustomerID, MIN(soh.OrderDate)AS OrderDate
INTO #MinOrderSates
>FROM Sales.SalesOrderHeader soh
GROUP BY soh.CustomerID
-- Do something additional with that information
SELECT soh.CustomerID, soh.SalesOrderID, soh.OrderDate
FROM Sales.SalesOrderHeader soh
JOIN #MinOrderDates t on soh.CustomerID = t.CustomerID and soh.OrderDate = t.OrderDate
ORDER BY soh.CustomerID
DROP TABLE #MinOrderDates;
有时,在不使用游标的情况下,使用多查询的方法是唯一的方法--不过这里并不是这样的。
SELECT sob1.CustomerID, sob1.SalesOrderID, sob1.OrderDate
FROM Sales.SalesOrderDetail soh1
WHERE soh1.OrderDate = (
SELECT Min(soh2.OrderDate) FROM Sales.SalesOrderDetail soh2
WHERE soh2.CustomerID = soh1.CustomerID
)
ORDER BY CustomerID;
在这个特殊查询中,外部查询只在 WHERE 子句中引用内部查询--也可以在选择列表中包含来自内部查询的数据。
SELECT sc.AccountNumber,
(SELECT Min(OrderDate) FROM Sales.SalesOrderHeader soh
WHERE sob.CustomerID = sc.CustomerID) AS OrderDate
FROM Sales.Customer sc;
USE AdventureWorks2008
CREATE TABLE Sales.MonthlyRollup
(
Year smallint NOT NULL,
Month tinyint NOT NULL,
ProductID int not null FOREIGN KEY REFERENCES Production.Product(ProductID),
QtySold int NOT NULL,
CONSTRAINT PKYearMonthProductID PRIMARY KEY(Year, Monh, ProductID)
);
编写 MERGE 语句如下
MERGE Sales.MonthlyRollup AS smr
USING
(
SELECT soh.OrderDate, sod.ProductID, SUM(sod.OrderQty) AS QtySold
FROM Sales.SalesOrderHeader soh
JOIN Sales.SalesOrderDetail sod on soh.SalesOrderID = sod.SalesOrderID
WHERE soh.OrderDate >= '2003-08-22' AND soh.OrderDate < '2003-08-23'
GROUP BY soh.OrderDate, sod.ProductID
) AS s
ON (s.ProductID = smr.ProductID)
WHEN MATCHED THEN
UPDATE SET smt.OtySold = smr.QtySold + s.QtySold
WHEN NOT MATCHED THEN
INSERT (Year, Month, ProductID, QtySold)
VALUES (DATEPART(yy, s.OrderDate),
DATEPART(m, s.OrderDate),
s.ProductID,
s.QtySold);