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

求助:查询过去三年每位客户平均订单数的SQL语句报错

解决SQL报错并实现“过去三年每位客户平均订单数”需求

咱们先拆解你遇到的问题:

为什么会报错?

你收到的错误提示“列 'Sales.SalesOrderDetail.ModifiedDate' 在HAVING子句中无效”,核心原因是:
HAVING子句只能用来过滤分组后的结果,它里面引用的字段要么是GROUP BY里的分组字段,要么是经过聚合函数(比如MAX()、MIN())处理后的字段。而你直接用了ModifiedDate,它既没在GROUP BY里,也没做聚合,数据库不知道该取分组里哪一条记录的这个值,自然就报错了。

另外,你的SQL还有几个和需求不匹配的逻辑问题:

  • 完全没关联客户表(Sales.Customer),根本拿不到客户信息,没法按客户统计;
  • GROUP BY SalesOrderDetailID, Name是按订单明细行+商品名称分组,这和“按客户分组”的目标完全不符;
  • 过滤“过去三年”的条件应该放在WHERE子句(分组前过滤数据),比用HAVING效率更高,也更合理。

针对需求的正确SQL写法

首先明确:“平均订单数”通常有两种理解,我分别给出对应的写法:

情况1:每位客户过去三年平均每年的订单数量

也就是总订单数除以3,得到年均订单数:

SELECT 
    c.CustomerID,
    p.FirstName + ' ' + p.LastName AS CustomerName,
    COUNT(DISTINCT soh.SalesOrderID) AS TotalOrders,
    COUNT(DISTINCT soh.SalesOrderID) / 3.0 AS AverageAnnualOrders
FROM Sales.Customer c
INNER JOIN Sales.SalesOrderHeader soh 
    ON c.CustomerID = soh.CustomerID
LEFT JOIN Person.Person p 
    ON c.PersonID = p.BusinessEntityID -- 关联Person表获取客户姓名(个人客户)
WHERE soh.OrderDate >= DATEADD(year, -3, GETDATE()) -- 过滤过去三年的订单
GROUP BY c.CustomerID, p.FirstName, p.LastName
ORDER BY AverageAnnualOrders DESC;

情况2:每位客户过去三年每个订单的平均商品数量

也就是总商品数量除以总订单数,得到单订单平均商品数:

SELECT 
    c.CustomerID,
    p.FirstName + ' ' + p.LastName AS CustomerName,
    COUNT(DISTINCT soh.SalesOrderID) AS TotalOrders,
    SUM(sod.OrderQty) AS TotalProducts,
    SUM(sod.OrderQty) / CAST(COUNT(DISTINCT soh.SalesOrderID) AS DECIMAL(10,2)) AS AverageProductsPerOrder
FROM Sales.Customer c
INNER JOIN Sales.SalesOrderHeader soh 
    ON c.CustomerID = soh.CustomerID
INNER JOIN Sales.SalesOrderDetail sod 
    ON soh.SalesOrderID = sod.SalesOrderID
LEFT JOIN Person.Person p 
    ON c.PersonID = p.BusinessEntityID
WHERE soh.OrderDate >= DATEADD(year, -3, GETDATE())
GROUP BY c.CustomerID, p.FirstName, p.LastName
ORDER BY AverageProductsPerOrder DESC;

几个关键说明

  • 用OrderDate而非ModifiedDate:OrderDate是订单创建的时间,更符合“过去三年订单”的统计逻辑;ModifiedDate是记录修改时间,可能不是你想要的;
  • COUNT(DISTINCT soh.SalesOrderID):因为一个订单对应多条明细行(SalesOrderDetail),必须去重才能得到真实的订单数量;
  • 用3.0或CAST(...) AS DECIMAL:避免整数除法导致的精度丢失,确保得到小数形式的平均值。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.14 09:04:52