关于CTE计算待结款项总额及现有款项统计SQL的正确性与优化问询
关于CTE计算待结款项总额及现有款项统计SQL的正确性与优化问询
嘿,我来帮你捋捋这个问题哈!从你描述的需求和贴出的代码片段来看,你是想统计每笔作业的已收、已付款项差额,重点展示**已收未付(差额>0)和已付未收(差额<0)**的情况,同时担心现有写法在大数据量下的性能问题对吧?
首先得说,你目前只贴了临时表@JobSImport的创建和数据插入部分,还没展示核心的统计查询逻辑,所以没法直接判断最终SQL的正确性,但我可以给你一些验证方向和优化建议:
一、正确性验证的关键点
- 明确款项定义:先确认
Paid(已付)和Collected(已收)的业务逻辑——比如Paid是公司对外支付的费用,Collected是从客户处收回的款项?差额计算要对应业务:如果是Collected - Paid,那>0就是客户给的钱比我们付出去的多,<0就是我们付出去的比收回来的多,这个逻辑要和你要展示的“Collected not paid”/“Paid not collected”对应上,别搞反了。 - 数据覆盖完整性:要确保统计逻辑涵盖了所有相关的发票和费用记录,比如有没有漏掉已取消、已作废的单据?
- 小数据集测试:用你贴的这几条测试数据手动计算差额,再跑你的SQL看结果是否一致,这是验证正确性最直接的方法。
二、大数据量下的优化建议
1. 用CTE替代临时表,减少IO开销
临时表在大数据量下会产生额外的磁盘写入开销,用CTE(公共表表达式)做中间统计更高效,给你一个示例逻辑参考:
WITH PaymentStats AS ( -- 联合发票和费用表,标记款项类型 SELECT JobNo, DepartmentId, DepartmentName, CustomerName, JobDate, 'Collected' AS PaymentType, Amount FROM Invoices UNION ALL SELECT JobNo, DepartmentId, DepartmentName, CustomerName, JobDate, 'Paid' AS PaymentType, Amount FROM Costs -- 先加过滤条件缩小数据范围,比如只查近段时间的记录 WHERE JobDate >= '2024-06-01' ) -- 分组统计并计算差额 SELECT JobNo, CONVERT(DATE, JobDate) AS JobDate, -- 建议把varchar转成date类型,避免隐式转换 DepartmentId, DepartmentName, CustomerName, SUM(CASE WHEN PaymentType = 'Collected' THEN Amount ELSE 0 END) - SUM(CASE WHEN PaymentType = 'Paid' THEN Amount ELSE 0 END) AS Balance, CASE WHEN SUM(CASE WHEN PaymentType = 'Collected' THEN Amount ELSE 0 END) - SUM(CASE WHEN PaymentType = 'Paid' THEN Amount ELSE 0 END) > 0 THEN 'Collected not paid' WHEN SUM(CASE WHEN PaymentType = 'Collected' THEN Amount ELSE 0 END) - SUM(CASE WHEN PaymentType = 'Paid' THEN Amount ELSE 0 END) < 0 THEN 'Paid not collected' END AS Status FROM PaymentStats GROUP BY JobNo, DepartmentId, DepartmentName, CustomerName, JobDate -- 只保留不平衡的记录,减少结果集大小 HAVING SUM(CASE WHEN PaymentType = 'Collected' THEN Amount ELSE 0 END) - SUM(CASE WHEN PaymentType = 'Paid' THEN Amount ELSE 0 END) <> 0 ORDER BY JobDate DESC, JobNo DESC;
2. 给核心表加复合索引
如果Invoices和Costs表数据量很大,一定要给这些字段建复合索引:
- 分组统计用:
(JobNo, PaymentType, Amount),能快速定位分组所需数据 - 按日期过滤的话,再加
JobDate:(JobDate, JobNo, PaymentType)
3. 优化数据类型
你临时表里的JobDate是varchar(10),建议改成DATE类型,避免查询时的隐式转换,排序和过滤都会更快。
4. 去掉不必要的字段
比如临时表里的FullPaid字段,你插入的都是0,如果业务上不需要,就删掉它,减少数据存储和传输的开销。
如果你能把完整的统计查询逻辑贴出来,我可以帮你更精准地判断正确性哦!
备注:内容来源于stack exchange,提问作者Adel Merhej
相关产品推荐
相关产品推荐

