Mysql 根据列的总和更新最早的行
我们有一个MySQL表来维护用户信用Mysql 根据列的总和更新最早的行,mysql,sql,Mysql,Sql,我们有一个MySQL表来维护用户信用 id user credits expiry status ----------------------------------------- 1 A 1.2 somedatetime 0 2 A 4.4 somedatetime 0 3 A 5.0 somedatetime 0 4 B
id user credits expiry status
-----------------------------------------
1 A 1.2 somedatetime 0
2 A 4.4 somedatetime 0
3 A 5.0 somedatetime 0
4 B 1.0 somedatetime 0
5 B 2.4 somedatetime 0
6 C 7.8 somedatetime 0
无论用户何时购买,我们都会从可用积分中扣除金额。为了对用户公平,将首先使用最接近到期日的信用卡,以此类推。我们还将更新状态以将行标记为已消费
例如,如果用户A购买了$2,则id 1将借记$1.2,id 2将借记$0.8,依此类推。所以这个表现在看起来像
id user credits expiry status
-----------------------------------------
1 A 0.0 somedatetime 1
2 A 3.6 somedatetime 1
3 A 5.0 somedatetime 0
4 B 1.0 somedatetime 0
5 B 2.4 somedatetime 0
6 C 7.8 somedatetime 0
到目前为止,我们一直采用暴力手段。任何关于如何在最小查询或单个查询中更有效地执行此操作的建议
更新:由于有人询问我们当前的暴力方法,它从最早的一行开始迭代每一行,并不断更新,直到涵盖购买金额,这是非常低效的
感谢您使用变量计算总学分。运行内部查询,以便首先了解什么是beign calculate
UPDATE customer c
JOIN (
SELECT cu.`id`,
cu.`user`,
`credits`, `expiry`, `status`,
@total := IF(@customer = cu.`user`, @total := @total + `credits`, `credits`) as cumulative_total,
@customer := cu.`user` as user_current,
`credit_used`
FROM customer cu
CROSS JOIN (SELECT @customer := '', @total := 0 ) t
JOIN credits
ON cu.`user` = credits.`user`
ORDER BY cu.`id`
) t
ON c.`id` = t.`id`
SET c.credits = CASE WHEN c.credits <= t.credit_used THEN 0
ELSE t.cumulative_total - credit_used
END,
c.status = CASE WHEN c.credits <= t.credit_used THEN 1
ELSE 0
END;
有人问过类似的问题。@草莓:请发布链接“暴力手段”是什么意思?@shadow一行一行地阅读并更新,直到购买金额被支付。其中$2,$1.2将从id 1中扣除,剩余$0.6我的数学不是很好,但我还有剩余的0.8
CREATE TABLE customer
(`id` int, `user` varchar(1), `credits` double, `expiry` int, `status` int)
;
INSERT INTO customer
(`id`, `user`, `credits`, `expiry`, `status`)
VALUES
(1, 'A', 1.2, 1, 0),
(2, 'A', 4.4, 2, 0),
(3, 'A', 5.0, 3, 0),
(4, 'B', 1.0, 4, 0),
(5, 'B', 2.4, 5, 0),
(6, 'C', 7.8, 6, 0)
;
CREATE TABLE credits
(`id` int, `user` varchar(1), `credit_used` double)
;
INSERT INTO credits
(`id`, `user`, `credit_used`)
VALUES
(1, 'A', 2.0),
(2, 'B', 3.4)
;
SET @amount = 2;
UPDATE t1
JOIN (
SELECT t2.id,
IF(@amount=0,t2.credits, IF(@amount>t2.credits,0,t2.credits-@amount)) credits,
IF(@amount>=t2.credits,@amount := @amount-t2.credits, 0)
FROM (
SELECT id, credits
FROM t1
WHERE credits>0 AND `user`='A'
ORDER BY expiry ASC
) t2
) t
ON t1.id = t.id
SET t1.credits=t.credits
WHERE t1.user = 'A';