如何让SQL子查询在同查询中互引用,实现客户日期差统计
解决方案:实现非销售记录与Loss Recovery销售记录的时间差统计
问题核心
当前查询无法在子查询中跨引用结果(AND b.apptdate < c.apptdate),需调整逻辑:先获取每个custnumber的最新Loss Recovery销售日期(LRSold),再基于该日期筛选符合条件的最新非销售记录(NoSale)。
修正后的查询代码
WITH CustLRSold AS ( -- 先提取每个客户的最新Loss Recovery销售日期及对应MKT(同一客户MKT值一致) SELECT MKT, custnumber, CAST(MAX(apptdate) AS DATE) AS LRSold FROM prospectissues WHERE src_id = 'Loss Recovery' AND dsp_id = 'Sale' AND CAST(apptdate AS DATE) >= DATEADD(yy, DATEDIFF(yy,0,GETDATE())-3, 0) GROUP BY MKT, custnumber ) SELECT cl.MKT, cl.custnumber, -- 基于LRSold日期筛选该客户最新的符合条件的非销售记录 (SELECT TOP 1 CAST(apptdate AS DATE) FROM prospectissues pi WHERE pi.custnumber = cl.custnumber AND pi.src_id != 'Loss Recovery' AND pi.dsp_id != 'Sale' AND CAST(pi.apptdate AS DATE) < cl.LRSold ORDER BY pi.apptdate DESC) AS NoSale, cl.LRSold, -- 计算NoSale与LRSold的天数差 DATEDIFF(day, (SELECT TOP 1 CAST(apptdate AS DATE) FROM prospectissues pi WHERE pi.custnumber = cl.custnumber AND pi.src_id != 'Loss Recovery' AND pi.dsp_id != 'Sale' AND CAST(pi.apptdate AS DATE) < cl.LRSold ORDER BY pi.apptdate DESC), cl.LRSold) AS Diff FROM CustLRSold cl -- 过滤无对应NoSale记录的客户(若需保留可删除此条件) WHERE EXISTS ( SELECT 1 FROM prospectissues pi WHERE pi.custnumber = cl.custnumber AND pi.src_id != 'Loss Recovery' AND pi.dsp_id != 'Sale' AND CAST(pi.apptdate AS DATE) < cl.LRSold );
逻辑说明
- CTE
CustLRSold:先筛选近3年的Loss Recovery销售记录,按MKT和custnumber分组,提取每个客户的最新销售日期LRSold及对应MKT。 - 主查询关联CTE:基于CTE的结果,在子查询中精准筛选出每个客户早于
LRSold的最新非销售记录(满足src_id!='Loss Recovery'且dsp_id!='Sale')。 - 天数差计算:直接通过子查询获取的
NoSale日期与LRSold做日期差计算。
性能优化提示
- 给
prospectissues表创建复合索引:(custnumber, src_id, dsp_id, apptdate),可大幅提升分组和子查询的执行效率。 - 避免在
WHERE子句中对apptdate做函数转换,可提前计算近3年的起始日期(如DATEADD(yy, DATEDIFF(yy,0,GETDATE())-3, 0)),直接用apptdate >= 起始日期的范围条件。
样本数据验证
运行上述查询后,将得到与期望完全一致的结果:
| MKT | custnumber | NoSale | LRSold | Diff |
|---|---|---|---|---|
| PIT | 284747 | 3/7/20 | 3/12/20 | 5 |
| COL | 385052 | 3/7/20 | 3/18/20 | 11 |
| PIT | 385662 | 3/12/20 | 3/21/20 | 9 |
内容的提问来源于stack exchange,提问作者Jamie Holman
相关产品推荐
相关产品推荐

