SQL使用Having子句未返回结果,三表条件查询求助
问题分析与修正方案
首先咱们先把你的需求拆解清楚,确保理解到位:
你需要返回所有满足以下任一条件的AccountNo:
- 该账号不在Givers表中;
- 该账号在Givers表中,同时满足:
- TakeMoney表中该账号在
'10-10-2020'的sum(MoneyTaken)小于 Yateem表中该账号的sum(Money)*3; - TakeMoney的记录日期匹配
'10-10-2020';
- TakeMoney表中该账号在
你的原SQL存在几个关键问题,导致没返回预期结果:
- 主表选得不对:原SQL以Givers为主表做左连接,直接漏掉了"不在Givers表中"的账号;
- 聚合函数用错了:把需求里的
sum(Yateem.Money)*3写成了COUNT(Yateem.Money)*3,完全偏离了计算逻辑; - 子查询没关联当前账号:子查询里没指定
AccountNo和外层查询关联,算出来的是所有账号的总和,不是当前账号的; - 过滤条件位置错了:HAVING子句里的
COUNT(Yateem.Money) >0过滤掉了Yateem中无记录的Givers账号,不符合需求; - 日期匹配方式不严谨:如果
date是日期类型,用LIKE不如直接用=准确(如果是字符串类型可以保留LIKE)。
修正后的SQL语句
下面是符合需求的SQL,我会把逻辑拆解得明明白白:
-- 先获取所有可能的AccountNo:涵盖Givers、Yateem、TakeMoney里的所有账号 WITH AllAccounts AS ( SELECT AccountNo FROM Givers UNION SELECT AccountNo FROM Yateem UNION SELECT AccountNo FROM TakeMoney ), -- 预计算每个账号在Yateem中的总金额 YateemTotal AS ( SELECT AccountNo, COALESCE(SUM(Money), 0) AS TotalYateemMoney FROM Yateem GROUP BY AccountNo ), -- 预计算每个账号在2020-10-10的TakeMoney总金额 TakeMoneyTotal AS ( SELECT AccountNo, COALESCE(SUM(MoneyTaken), 0) AS TotalTaken FROM TakeMoney WHERE date = '10-10-2020' -- 如果date是字符串类型,用LIKE也可,但=更精准 GROUP BY AccountNo ) SELECT aa.AccountNo FROM AllAccounts aa LEFT JOIN Givers g ON aa.AccountNo = g.AccountNo LEFT JOIN YateemTotal yt ON aa.AccountNo = yt.AccountNo LEFT JOIN TakeMoneyTotal tmt ON aa.AccountNo = tmt.AccountNo WHERE -- 条件1:账号不在Givers表中 g.AccountNo IS NULL OR -- 条件2:账号在Givers表中,且满足sum(MoneyTaken) < sum(Money)*3 ( g.AccountNo IS NOT NULL AND tmt.TotalTaken < yt.TotalYateemMoney * 3 -- 确保该账号在TakeMoney中有2020-10-10的记录 AND tmt.AccountNo IS NOT NULL );
关键逻辑说明
- AllAccounts CTE:通过UNION收集所有出现过的AccountNo,确保不会漏掉不在Givers里的账号;
- YateemTotal和TakeMoneyTotal CTE:提前算好每个账号的聚合值,避免重复计算,逻辑也更清晰;
- WHERE条件:明确拆分两个需求分支,每个条件都精准匹配:
- 第一个分支直接判断账号不在Givers中;
- 第二个分支先确认账号在Givers中,再判断TakeMoney总金额小于Yateem总金额的3倍,同时确保该账号在TakeMoney中有指定日期的记录;
如果你的date字段是日期类型,建议把'10-10-2020'改成数据库支持的标准日期格式(比如'2020-10-10'),避免格式匹配出问题。
内容的提问来源于stack exchange,提问作者SomeOne
相关产品推荐
相关产品推荐

