AdventureWorks数据库SQL查询错误排查——《Beginning Microsoft SQL Server® 2008 Programming》中消费超70000美元账户最新5笔订单查询问题
问题分析:AdventureWorks数据库查询错误排查
你的需求是显示从在AdventureWorks消费总额超过70000美元的账户中产生的最新5笔订单,咱们先拆解一下你写的SQL里的几个关键问题:
原查询的错误点
SELECT ss.AccountNumbeR, OrderDate FROM Sales.SalesOrderHeader ss WHERE ss.TotalDue > 70000 AND ss.AccountNumber NOT IN ( SELECT TOP 5 ss.AccountNumber FROM Sales.SalesOrderDetail so JOIN Sales.SalesOrderHeader ss ON SO.SalesOrderID = ss.SalesOrderID HAVING SUM(so.LineTotal > 70000) ) GROUP BY ss.TotalDue, ss.AccountNumber, OrderDate ORDER BY OrderDate DESC
- 逻辑方向完全搞反:你用了
NOT IN,这会排除掉子查询里的账户,但你实际需要的是保留这些消费超70000的账户的订单,直接和需求背道而驰。 - 子查询语法错误:
HAVING SUM(so.LineTotal > 70000)是无效写法——首先SUM()里的条件表达式会被当作布尔值(0或1)求和,这不是你要的“消费总额超过70000”;其次HAVING必须配合GROUP BY使用,子查询里没有分组,语法上根本通不过。 - 不必要的GROUP BY:
Sales.SalesOrderHeader里每一行对应一笔订单,TotalDue是单订单的总金额,你按TotalDue分组会把相同金额的订单合并,丢失你需要的订单记录,完全没必要。 - 子查询排序缺失:子查询里的
TOP 5没有指定排序规则,取到的账户是随机的,完全不符合“最新”的逻辑。 - 表别名混淆:主查询和子查询都用
ss作为SalesOrderHeader的别名,会导致解析歧义,可读性也极差。
正确的查询思路与代码
首先我们需要先筛选出所有消费总额超过70000美元的账户(按账户分组,计算该账户所有订单的总金额),然后从这些账户的订单中取出最新的5笔(按订单日期倒序排序后取TOP 5)。
-- 先获取消费总额超70000的账户,再取这些账户的最新5笔订单 SELECT TOP 5 soh.AccountNumber, soh.OrderDate FROM Sales.SalesOrderHeader soh WHERE soh.AccountNumber IN ( -- 子查询:计算每个账户的总消费额,筛选出超过70000的账户 SELECT AccountNumber FROM Sales.SalesOrderHeader GROUP BY AccountNumber HAVING SUM(TotalDue) > 70000 ) ORDER BY soh.OrderDate DESC;
如果你的需求是“有单订单金额超过70000的账户的最新5笔订单”(注意和“账户总消费超70000”的区别),可以调整为:
-- 有单订单金额超70000的账户,取他们的最新5笔订单 SELECT TOP 5 soh.AccountNumber, soh.OrderDate FROM Sales.SalesOrderHeader soh WHERE soh.AccountNumber IN ( SELECT DISTINCT AccountNumber FROM Sales.SalesOrderHeader WHERE TotalDue > 70000 ) ORDER BY soh.OrderDate DESC;
两种写法的区别在于:前者是账户所有订单的总金额超70000,后者是该账户至少有一笔订单金额超70000,你可以根据实际需求选择。
内容的提问来源于stack exchange,提问作者TOP 10
相关产品推荐
相关产品推荐

