SQL查询异常排查:筛选超3年服务发票却出现近期发票问题
解决SQL查询中获取超3年服务发票及休眠客户的问题
问题分析
从你的描述来看,查询结果不符合预期的核心原因是分组逻辑出现了偏差,同时你还需要覆盖“过去3年未开展服务业务的客户”这一需求。先拆解原SQL的问题点:
- 分组字段错误:你用了
sih.name(服务发票表头的名称)而非客户表的c.[Name]分组,这会导致同一个客户因发票表头名称不同被拆分成多个分组,计算出的MAX(Posting Date)并非该客户的整体最后发票日期,从而混入日期不足3年的记录。 - 关联逻辑冗余:第一个需求是获取已开票客户的信息,
LEFT JOIN会引入无发票的客户,改用INNER JOIN更精准。
解决方案1:获取每个已开票客户的最后一张超3年服务发票
修正分组字段并调整关联逻辑后,SQL如下:
SELECT c.[No_] AS 'Customer No.', c.[Name] AS 'Customer Name', MAX(sih.[No_]) AS 'Last Service Invoice No.', MAX(sih.[Posting Date]) AS 'Last Service Invoice Posting Date' FROM [Service Invoice Header] sih INNER JOIN [Customer] c ON sih.[Customer No_] = c.[No_] GROUP BY c.[No_], c.[Name] HAVING MAX(sih.[Posting Date]) < DATEADD(YEAR, -3, GETDATE()) ORDER BY c.[Name]
关键调整说明:
- 按客户的编号和名称分组,确保每个客户只返回一行,计算的是该客户所有服务发票中的最新日期和发票号。
INNER JOIN确保只返回有服务发票记录的客户。HAVING子句严格筛选出最后一张发票日期已超过3年的客户,彻底避免出现日期不符合的记录。
解决方案2:找出过去3年未开展服务业务的客户
这类客户包含两种:从未有过服务发票的客户,以及最后一张发票日期超过3年的客户。推荐两种实现方式:
方式A:LEFT JOIN + GROUP BY(直观易懂)
SELECT c.[No_] AS 'Customer No.', c.[Name] AS 'Customer Name', MAX(sih.[Posting Date]) AS 'Last Service Invoice Posting Date' FROM [Customer] c LEFT JOIN [Service Invoice Header] sih ON c.[No_] = sih.[Customer No_] GROUP BY c.[No_], c.[Name] HAVING MAX(sih.[Posting Date]) IS NULL -- 从未产生过服务发票 OR MAX(sih.[Posting Date]) < DATEADD(YEAR, -3, GETDATE()) -- 最后发票超3年 ORDER BY c.[Name]
方式B:NOT EXISTS(性能更优,适合大表)
逻辑更直接:筛选过去3年没有任何服务发票记录的客户:
SELECT [No_] AS 'Customer No.', [Name] AS 'Customer Name' FROM [Customer] c WHERE NOT EXISTS ( SELECT 1 FROM [Service Invoice Header] sih WHERE sih.[Customer No_] = c.[No_] AND sih.[Posting Date] >= DATEADD(YEAR, -3, GETDATE()) ) ORDER BY [Name]
内容的提问来源于stack exchange,提问作者Craig Zirnheld
相关产品推荐
相关产品推荐

