You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

基于AdventureWorks2017,查询同时有指定前后时间段订单的客户姓名的SQL问题

解决AdventureWorks中筛选跨时间段订单客户的问题

让我们先拆解你遇到的问题,然后一步步给出正确的解决方案:

为什么初始查询返回0行?

你的初始查询存在一个核心逻辑错误:你试图让同一个sales_order_table的OrderDate同时满足<= '2012-09-30'和>= '2013-06-30'——一个日期不可能同时早于2012年9月又晚于2013年6月,这种关联条件永远无法成立,自然返回0行数据。

修改后查询的边界问题

你后续的查询用NOT BETWEEN+COUNT(*) >=2的方式,会错误地包含那些仅在单个时间段有多次订单的客户(比如2012年前有3笔订单,2013年后没有),这不符合你"同时在两个时间段都有订单"的核心需求。

正确的解决方案

这里提供两种可靠的实现方式,按需选择:

方法1:使用EXISTS子查询(逻辑直观,易维护)

直接检查每个客户是否同时存在两个时间段的订单:

SELECT DISTINCT p.FirstName, p.MiddleName, p.LastName
FROM Person.Person p
JOIN Sales.Customer c ON p.BusinessEntityID = c.PersonID
WHERE EXISTS (
    -- 检查客户是否有2012-09-30之前的订单
    SELECT 1
    FROM Sales.SalesOrderHeader soh
    WHERE soh.CustomerID = c.CustomerID
      AND soh.OrderDate <= '2012-09-30'
)
AND EXISTS (
    -- 检查客户是否有2013-09-30之后的订单
    SELECT 1
    FROM Sales.SalesOrderHeader soh
    WHERE soh.CustomerID = c.CustomerID
      AND soh.OrderDate >= '2013-09-30'
);

方法2:使用分组+条件聚合(大数据量下性能更优)

通过一次扫描订单表,统计每个客户在两个时间段的订单数,确保每个时间段至少有1笔:

SELECT p.FirstName, p.MiddleName, p.LastName
FROM Person.Person p
JOIN Sales.Customer c ON p.BusinessEntityID = c.PersonID
JOIN Sales.SalesOrderHeader soh ON c.CustomerID = soh.CustomerID
-- 用BusinessEntityID分组更可靠,避免同名不同人被错误合并
GROUP BY p.BusinessEntityID, p.FirstName, p.MiddleName, p.LastName
HAVING 
    -- 统计2012-09-30前的订单数,至少1笔
    COUNT(CASE WHEN soh.OrderDate <= '2012-09-30' THEN 1 END) >= 1
    -- 统计2013-09-30后的订单数,至少1笔
    AND COUNT(CASE WHEN soh.OrderDate >= '2013-09-30' THEN 1 END) >= 1;

注意事项

  • 你原始需求中是2013-09-30之后,但修改版查询写的是2013-06-30,请确保使用符合业务需求的日期值。
  • 分组时优先使用BusinessEntityID(唯一标识)而不是仅用姓名,避免同名客户被错误合并。

内容的提问来源于stack exchange,提问作者Lathezar Mitev

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.08 08:43:13