双Outer Apply联用返回相同统计结果的SQL问题排查
问题原因分析
同时使用两个OUTER APPLY返回明细行时,两个子查询的结果会形成笛卡尔积(交叉连接)。比如D返回5条222类型交易,E返回1条111类型交易,联用后主表的每一行会和5×1=5条组合行关联,导致count(e.MKey)和count(d.Key)都统计为5,而非各自真实的数量。
另外原代码存在明显错误:两个OUTER APPLY的tTypeID都写为1111,与你描述的"分别获取111、222类型交易"不符,需要修正对应的值。
解决方案
将每个OUTER APPLY改为直接返回统计结果(数量、金额),而非明细行,这样每个OUTER APPLY只会返回一行数据,彻底避免笛卡尔积问题。
修正后的SQL代码
SELECT f.dID, f.edID, f.tTypeID, f.Amount, f.MKey, ISNULL(e.TransCount, 0) [111 Trans], ISNULL(e.AmountSum, 0) [111 Amount], ISNULL(d.TransCount, 0) [222 Trans], ISNULL(d.AmountSum, 0) [222 Amount] FROM wh.fct.Account f JOIN wh.fct.ttype tt ON tt.tTypeID = f.tTypeID AND tt.bID = 3 AND f.dID >= 20221101 AND tt.TrnCode = 1234 AND f.MKey = 1234 OUTER APPLY( SELECT COUNT(*) TransCount, SUM(f1.Amount) AmountSum FROM wh.fct.Account f1 WHERE f1.MKey = 1234567 AND f1.tTypeID = 2222 -- 替换为222类型对应的真实tTypeID AND f1.bID = 3 AND CONVERT(datetime, CONVERT(char(8), f1.edID)) BETWEEN CONVERT(datetime, CONVERT(char(8), f.edID)) AND DATEADD(DAY, 10, CONVERT(datetime, CONVERT(char(8), f.edID))) ) D OUTER APPLY( SELECT COUNT(*) TransCount, SUM(f2.Amount) AmountSum FROM wh.fct.Account f2 WHERE f2.MKey = 1234567 AND f2.tTypeID = 1111 -- 替换为111类型对应的真实tTypeID AND f2.bID = 3 AND CONVERT(datetime, CONVERT(char(8), f2.edID)) BETWEEN CONVERT(datetime, CONVERT(char(8), f.edID)) AND DATEADD(DAY, 10, CONVERT(datetime, CONVERT(char(8), f.edID))) ) E
关键说明
- 每个
OUTER APPLY内部直接完成统计,仅返回一行包含数量和金额的结果,避免了两个子查询结果的交叉连接。 - 使用
ISNULL处理无匹配交易的情况,确保统计值显示为0而非NULL。 - 修正了原代码中两个
OUTER APPLY的tTypeID相同的错误,请根据实际业务替换为111、222类型对应的真实tTypeID值。
内容的提问来源于stack exchange,提问作者user7046806
相关产品推荐
相关产品推荐

