含CROSS APPLY的SQL Server复杂查询转SQLite的求助
SQLite 版查询适配方案
原SQL Server语句里的CROSS APPLY作用是逐行匹配客户信息,分别计算每个客户的累计交易总额、累计已支付金额,最终计算两者差值即客户欠款。SQLite本身不支持CROSS APPLY语法,可根据实际数据规模选择以下两种完全等价的改写方式。
1:1 逻辑匹配写法
这种写法完全对齐原查询的输出结果,适配成本最低,适合数据量不大的场景:
SELECT c.cust_id, c.name, c.phone, COALESCE((SELECT SUM(tr.final) FROM transfers tr WHERE tr.cust_id = c.cust_id), 0) AS price, COALESCE((SELECT SUM(tp.value) FROM trans_payments tp WHERE tp.cust_id = c.cust_id), 0) AS paid, COALESCE((SELECT SUM(tr.final) FROM transfers tr WHERE tr.cust_id = c.cust_id), 0) - COALESCE((SELECT SUM(tp.value) FROM trans_payments tp WHERE tp.cust_id = c.cust_id), 0) AS debt, c.location, c.note, c.date FROM Customers c
- 逻辑对齐说明:原查询中通过
COALESCE将无交易记录的客户的聚合值转为0,该写法完全保留了这一逻辑——哪怕客户没有任何转账、支付记录,也不会被过滤,对应聚合字段会返回0值。
性能优化写法
如果客户、交易明细的数据量较大,逐行执行子查询会产生不必要的性能损耗,可采用预聚合后关联的写法,整体查询效率更高:
SELECT c.cust_id, c.name, c.phone, COALESCE(tr.total_price, 0) AS price, COALESCE(tp.total_paid, 0) AS paid, COALESCE(tr.total_price, 0) - COALESCE(tp.total_paid, 0) AS debt, c.location, c.note, c.date FROM Customers c LEFT JOIN ( -- 先按客户维度预计算所有客户的累计转账总额 SELECT cust_id, SUM(final) AS total_price FROM transfers GROUP BY cust_id ) tr ON tr.cust_id = c.cust_id LEFT JOIN ( -- 先按客户维度预计算所有客户的累计支付总额 SELECT cust_id, SUM(value) AS total_paid FROM trans_payments GROUP BY cust_id ) tp ON tp.cust_id = c.cust_id
- 注意事项:两个明细聚合关联必须使用
LEFT JOIN,如果换成INNER JOIN,无交易记录的客户会被直接过滤,和原查询的返回结果不一致。如果transfers、trans_payments表的cust_id字段建立了索引,这种写法的查询速度会优于逐行执行子查询的方案。
内容的提问来源于stack exchange,提问作者Rabeea qabaha
相关产品推荐
相关产品推荐

