AdventureWorks2017数据库SQL查询求助:筛选特定年份下单客户
解决AdventureWorks2017的客户订单年份筛选问题
嘿,我来帮你搞定这个查询问题!你遇到的问题其实很常见——用WHERE子句没法直接判断一个客户的跨年份订单情况,因为WHERE是针对单条记录过滤的,没法同时检查一个客户是否存在多个不同年份的订单。咱们换个思路,用分组筛选或者子查询来实现需求。
方法一:用CTE(公共表表达式)分步筛选
这种方法逻辑清晰,先找出符合条件的客户,再统计他们的订单数量:
WITH CustomerOrderYears AS ( -- 先整理每个客户所有的下单年份(去重,避免同一年多次订单重复统计) SELECT CustomerID, YEAR(OrderDate) AS OrderYear FROM Sales.SalesOrderHeader GROUP BY CustomerID, YEAR(OrderDate) ), QualifiedCustomers AS ( -- 筛选出同时有2011、2014年订单,且无2012、2013年订单的客户 SELECT CustomerID FROM CustomerOrderYears GROUP BY CustomerID HAVING -- 存在2011年订单 SUM(CASE WHEN OrderYear = 2011 THEN 1 ELSE 0 END) > 0 -- 存在2014年订单 AND SUM(CASE WHEN OrderYear = 2014 THEN 1 ELSE 0 END) > 0 -- 完全没有2012、2013年订单 AND SUM(CASE WHEN OrderYear IN (2012, 2013) THEN 1 ELSE 0 END) = 0 ) -- 统计符合条件的客户在2011、2014年的订单数量 SELECT soh.CustomerID, YEAR(soh.OrderDate) AS [year], COUNT(soh.SalesOrderID) AS ordersQTY FROM Sales.SalesOrderHeader soh JOIN QualifiedCustomers qc ON soh.CustomerID = qc.CustomerID WHERE YEAR(soh.OrderDate) IN (2011, 2014) GROUP BY soh.CustomerID, YEAR(soh.OrderDate) ORDER BY soh.CustomerID, [year];
方法二:用EXISTS/NOT EXISTS直接筛选
这种方式更直观,直接在WHERE子句里通过子查询判断客户的订单年份情况:
SELECT CustomerID, YEAR(OrderDate) AS [year], COUNT(SalesOrderID) AS ordersQTY FROM Sales.SalesOrderHeader soh WHERE -- 只统计2011和2014年的订单 YEAR(OrderDate) IN (2011, 2014) -- 该客户存在2011年订单 AND EXISTS ( SELECT 1 FROM Sales.SalesOrderHeader soh2 WHERE soh2.CustomerID = soh.CustomerID AND YEAR(soh2.OrderDate) = 2011 ) -- 该客户存在2014年订单 AND EXISTS ( SELECT 1 FROM Sales.SalesOrderHeader soh2 WHERE soh2.CustomerID = soh.CustomerID AND YEAR(soh2.OrderDate) = 2014 ) -- 该客户完全没有2012、2013年订单 AND NOT EXISTS ( SELECT 1 FROM Sales.SalesOrderHeader soh2 WHERE soh2.CustomerID = soh.CustomerID AND YEAR(soh2.OrderDate) IN (2012, 2013) ) GROUP BY CustomerID, YEAR(OrderDate) ORDER BY CustomerID, [year];
为什么WHERE子句单独用不行?
你之前用WHERE没得到正确结果,核心原因是WHERE是对单条记录做过滤——一条订单记录的年份只能是某一年,你没法写出YEAR(OrderDate)=2011 AND YEAR(OrderDate)=2014这种条件(这本身矛盾)。必须先按客户维度聚合,检查他们的所有订单年份集合是否符合要求,再去统计对应年份的订单数。
注意:确保你用的表和字段是AdventureWorks2017的正确值——订单表是Sales.SalesOrderHeader,客户ID字段是CustomerID,订单日期是OrderDate,这些在2017版本里是标准的。
内容的提问来源于stack exchange,提问作者Luq Sparrow
相关产品推荐
相关产品推荐

