用普通T-SQL语句代替游标操作
经常写SQL的同学们都知道, 在Sql Server的IDE中如果SQL嵌套的层次太多, 查看和修改代码将变得非常痛苦, 再加上游标用得不恰当很容易出现"锁"和"性能"问题.
所以通常大大们都劝大家尽量少用游标, 阿飞个人很喜欢将业务逻辑写在存储过程里, 于是也经常遇到需要游标逻辑的地方, 这里就跟大家分享一点使用普通T-SQL语句代替游标的处理方案.
业务需求:
订单表 t_orders (id int, total money, paid money, date datetime)
付款单 t_pays (id int, amount money, date datetime)
付款单和订单关系表 t_relation (pay_id int, order_id int, amount money)
财务付款时, 往 t_pays 插入一条记录, 并且需要按照订单表的时间顺序在 t_relation 表标记出此次付款用于支付了哪些订单, 一个付款单可能会对应多个订单, 一个订单也可能分几次支付, 所以 t_relation 表中存储的是多对多的关系.
存储过程的输入参数 @amount money, 表示此次支付金额
1. 首先插入 t_pays 记录, set @pay_id = SCOPE_IDENTITY(); 获取此次付款单编号
2. 使用一个变量表来存储需要支付的订单
--amount 表示此订单需要支付的金额, pay 表示此次将要支付的金额, sort 用来表示支付顺序 declare @orders table(id int, amount money, pay money, sort int); --使用CTE(Common Table Expressions)列出所有需要支付的订单 with REF(id, amount, sort) as ( select id, total - paid, Row_Number()over(order by date) from t_orders where total > paid ) --然后筛选出此次可以支付的订单, 插入到变量表
--需要注意的是, 普通订单此次支付的金额是 total - paid, 但是最后一个订单, 付款单金额如果不足(@amount < balance)就应该是 @amount - (balance - amount) insert into @orders(id, amount, sort, pay) select K.id, K.amount, K.sort, case when @amount >= T.balance then K.amount else @amount - (T.balance - K.amount) end from REF as K outer apply ( select IsNull(sum(amount), 0) as balance from REF where sort <= K.sort )T where @amount > T.balance - K.amount --这里, T表累加了到K表当前记录为止的应付总额, --可支付的订单应满足的条件是: 付款单金额@amount > 我前面一个订单为止的总额( 即 balance - amount)
3. 开始向关系表插入记录
insert into t_relation(pay_id, order_id, amount) select @pay_id, id, pay from @orders;
4. 更新t_orders 表的 已付金额(paid)
update T set T.paid = T.paid + K.pay from @orders K inner join t_orders T on T.id = K.id
大功告成, 看起来好像有很多语句, 仔细数一下, 其实完成"关系链接"的只有三条语句.