第四章.子查询

文章目录

      • 4.1 自包含子查询
        • 4.1.1 自包含标量子查询示例
        • 4.1.2 自包含多值查询
      • 4.2 相关子查询
        • 4.2.1 EXISTS 谓词
      • 4.3 超越子查询基础知识
        • 4.3.1 返回前一个或下一个值
        • 4.3.2 使用运行聚合
      • 练习

4.1 自包含子查询

4.1.1 自包含标量子查询示例

--获取订单号最大的订单的信息
DECLARE @maxid INT = (SELECT MAX(orderid) FROM Sales.Orders)

SELECT orderid,orderdate,empid,custid
FROM Sales.Orders
WHERE orderid = @maxid

#嵌入式代码实现-标量子查询
SELECT orderid,orderdate,empid,custid
FROM Sales.Orders
WHERE orderid = (SELECT MAX(orderid) FROM Sales.Orders)
#标量子查询返回多个值,查询会失效

--返回有姓氏以字母B开头的任意雇员的订单id
SELECT E.empid FROM HR.Employees AS E 
	 WHERE E.lastname LIKE N'B%'
#先执行以上内容,发现以B开头的雇员只有一个,所以以下执行正常	 
SELECT orderid 
FROM Sales.Orders 
WHERE empid = (SELECT E.empid FROM HR.Employees AS E 
	 WHERE E.lastname LIKE N'B%')
--返回有姓氏中含有a的雇员的订单id
SELECT E.empid FROM HR.Employees AS E 
	 WHERE E.lastname LIKE N'%a%'
#先执行以上代码发现姓氏中有a的雇员有三个所以导致下面查询无效
SELECT orderid 
FROM Sales.Orders 
WHERE empid = (SELECT E.empid FROM HR.Employees AS E 
	 WHERE E.lastname LIKE N'%a%')

4.1.2 自包含多值查询

--返回姓氏以D开头的雇员所在的订单号
SELECT orderid 
FROM Sales.Orders 
WHERE empid IN (SELECT E.empid FROM HR.Employees AS E 
	 WHERE E.lastname LIKE N'D%')
#连接查询
SELECT O.orderid FROM Sales.Orders AS O JOIN HR.Employees AS E 
		ON O.empid = E.empid
WHERE E.lastname LIKE N'D%'

--返回有美国客户的订单id
SELECT * 
FROM Sales.Orders AS O
WHERE O.custid IN (
	SELECT
		C.custid
	FROM Sales.Customers AS C
	WHERE C.country = 'USA'
)
#NOT IN 即可查询非美国用户
SELECT * 
FROM Sales.Orders AS O
WHERE O.custid NOT IN (
	SELECT
		C.custid
	FROM Sales.Customers AS C
	WHERE C.country = 'USA'
)

--创建一个dbo.Orders表 里面存储Sales.Orders中偶数的订单号
CREATE TABLE dbo.Orders(orderid INT NOT NULL CONSTRAINT PK_Orders PRIMARY KEY);
INSERT INTO dbo.Orders(orderid)
		SELECT orderid
		FROM Sales.Orders
		WHERE orderid % 2 = 0
--获取dbo.Nums表中介于dbo.Orders表中订单号最大与最小之间的值且不存在于dbo.Orders表中
--其实最终结果就是Sales.Orders表中订单号为单数的订单号
SELECT n
FROM dbo.Nums
WHERE n BETWEEN (SELECT MIN(O.orderid) FROM dbo.Orders AS O)
		AND (SELECT MAX(O.orderid) FROM dbo.Orders AS O)
	AND n NOT IN (SELECT O.orderid FROM dbo.Orders AS O)

4.2 相关子查询

--先从O1中取一个custid在子查询中获取这个custid的最大orderid·
SELECT
	custid,orderid,orderdate,empid 
FROM Sales.Orders AS O1
WHERE O1.orderid = (
	SELECT
		MAX(O2.orderid)
	FROM Sales.Orders AS O2
	WHERE O2.custid = O1.custid
)

--从O1取一行数据,然后根据这行查询结果的custid在子查询中获取这个用户的的所有订单值的总和,用这行查询的订单值除以总的订单值再乘100获取这个订单值在用户总订单值中的百分比占比
--CAST(....AS NUMERIC(5,2))表示这个百分比占比总共有五位其中小数点后占了两位符合百分比的规则
SELECT 
	orderid,custid,val,
	CAST(100. * O1.val / (SELECT SUM(O2.val)
						FROM Sales.OrderValues AS O2
						WHERE O2.custid = O1.custid)
						AS NUMERIC(5,2)) AS pct
FROM Sales.OrderValues AS O1
ORDER BY custid,orderid
#下面是查询结果将custid = 1或2的pct值相加结果是100
orderid     custid      val                                     pct
----------- ----------- --------------------------------------- -----------------
10643       1           814.50                                  19.06
10692       1           878.00                                  20.55
10702       1           330.00                                  7.72
10835       1           845.80                                  19.79
10952       1           471.20                                  11.03
11011       1           933.50                                  21.85
10308       2           88.80                                   6.33
10625       2           479.75                                  34.20
10759       2           320.00                                  22.81
10926       2           514.40                                  36.67
10365       3           403.20                                  5.74

4.2.1 EXISTS 谓词

谓词EXISTS可接受一个查询作为输入。如果子查询作为任意行,谓词返回true否则返回false

--先获取一个西班牙客户的的信息,然后判断这个西班牙客户是否有订单存在,有的话返回客户信息                   
SELECT
	custid,companyname
FROM Sales.Customers AS C
WHERE country = N'Spain'
	AND  EXISTS(
		SELECT * FROM Sales.Orders AS O
		WHERE O.custid = C.custid
	)

4.3 超越子查询基础知识

4.3.1 返回前一个或下一个值

--O1先查询出一行然后在O2中查询在O1订单之前运费最高额
--返回的结果就是每一单之前的运费最高额
SELECT 
	orderid,orderdate,empid,custid,
	(
		SELECT
			MAX(freight)
		FROM Sales.Orders AS O2
		WHERE O2.orderdate < O1.orderdate
	)AS premaxfreight
FROM Sales.Orders AS O1

4.3.2 使用运行聚合

运行聚合是随着时间积累值得聚合

--返回每年和之前总的qty,最后按照年排序
SELECT 
	orderyear,qty,
	(
		SELECT
			SUM(O2.qty)
		FROM Sales.OrderTotalsByYear AS O2
		WHERE O2.orderyear <= O2.orderyear
	) AS runqty
FROM Sales.OrderTotalsByYear AS O1
ORDER BY orderyear

练习

--4.5.1
#活动最后一天下得所有订单
SELECT 
	orderid,orderdate,custid,empid
FROM Sales.Orders AS O1
WHERE O1.orderdate = (
	SELECT 
		MAX(O2.orderdate)
	FROM Sales.Orders AS O2
)

--4.5.2
#查询数量最多的客户的所有订单
#最内层用TOP查询订单最多的有多少单,次内层根据订单数量将选出有这么多订单的用户id,最外层根据用户id将他们所有的订单信息查出来
SELECT
	custid,orderid,orderdate,empid
FROM Sales.Orders AS O1
WHERE O1.custid IN (
	SELECT
		custid
	FROM Sales.Orders AS O2
	GROUP BY custid
	HAVING COUNT(O2.orderid) = (
		SELECT 
			TOP(1) WITH TIES COUNT(O3.orderid)
		FROM Sales.Orders AS O3
		GROUP BY O3.custid
		ORDER BY COUNT(O3.orderid) DESC
	)
)
--4.5.3
#返回2008年5月1日或之后没有下单的雇员
SELECT 
	empid,firstname,lastname
FROM HR.Employees 
WHERE empid NOT IN (
	SELECT 
		empid
	FROM Sales.Orders
	WHERE orderdate > '20080501'
)
--4.5.4
#返回有客户但是没有雇员的国家
SELECT
	DISTINCT country
FROM Sales.Customers
WHERE country NOT IN (
	SELECT
		country
	FROM HR.Employees
)
--4.5.5
#返回客户活动最后一天下的所有订单
SELECT
	custid,orderid,orderdate ,empid
FROM Sales.Orders AS O1
WHERE orderdate = (
	SELECT
		MAX(O2.orderdate)
	FROM Sales.Orders AS O2
	WHERE O1.custid = O2.custid
)

--4.5.6
#返回2007年下单但是2008年没有下单的客户
SELECT
	custid,companyname
FROM Sales.Customers
WHERE custid IN (
	SELECT
		custid
	FROM Sales.Orders
	WHERE orderdate >= '20070101' AND orderdate < '20080101' 
) AND custid NOT IN(
	SELECT
		custid
	FROM Sales.Orders
	WHERE orderdate >= '20080101' AND orderdate < '20090101' 
)
--4.5.7
#返回订购了产品12的用户
SELECT
	DISTINCT
	C.custid,companyname
FROM Sales.Customers AS C JOIN Sales.Orders AS O ON C.custid = O.custid
WHERE orderid IN(
	SELECT
		orderid
	FROM Sales.OrderDetails
	WHERE productid = 12
)
#使用exists的另一种方法
SELECT
	custid,companyname
FROM Sales.Customers AS C
WHERE EXISTS(
	SELECT
		custid
	FROM Sales.Orders AS O
	WHERE C.custid = O.custid AND EXISTS(
		SELECT 
			*
		FROM Sales.OrderDetails AS OD
		WHERE productid = 12 AND O.orderid = OD.orderid
	)
)
--4.5.7
SELECT
	custid,ordermonth,qty,(
		SELECT
			SUM(CO2.qty)
		FROM Sales.CustOrders AS CO2
		WHERE CO1.custid = CO2.custid
			AND CO2.ordermonth <= CO1.ordermonth
	  )
FROM Sales.CustOrders AS CO1
ORDER BY custid,ordermonth

你可能感兴趣的:(数据库)