2016-06-16 2 views
1

사용자 크레딧을 유지하기 위해 다음 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  1.0  somedatetime 0 
5  B  2.4  somedatetime 0 
6  C  7.8  somedatetime 0 

사용자가 구매할 때마다 사용 가능한 크레딧에서 금액을 차감합니다. 사용자에게 공정하기 위해 가장 가까운 만료 크레딧이 먼저 소비됩니다. 행을 소비 한 것으로 표시하도록 상태를 업데이트합니다.

예를 들어 사용자 A가 $ 2를 (를) 구매하면 $ 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 

지금까지 우리는 brute-force 접근 방식으로 작업 해 왔습니다. 모든 아이디어는 최소 또는 단일 쿼리에서보다 효율적으로 작업하는 방법을 제안합니다.

업데이트 : 누군가가 현재의 무차별 대입 접근법에 대해 물어 봤기 때문에 구입 금액이 충당 할 때까지 가장 오래된 것부터 업데이트되는 각 행을 반복하므로 매우 비효율적입니다.

감사합니다.

+0

비슷한 질문이 요구되고있다. – Strawberry

+0

@Strawberry : 링크 게시하기 –

+0

'무차별 대입'이란 무엇을 의미합니까? – Shadow

답변

3

변수를 사용하여 총 크레딧을 계산합니다. 내부 쿼리를 실행하여 먼저 계산되는 beign을 배웁니다.

Fiddle Demo

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; 

내 테스트 설정 :

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) 
; 
+0

Juan에게 감사드립니다. 훌륭합니다. – yumoji

0

http://sqlfiddle.com/#!9/485673/1

SET @amount = 2; 
UPDATE t1 
JOIN (
    SELECT t2.id, 
    IF(@amount=0,t2.credits, IF(@amount>t2.credits,0,[email protected])) 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'; 
관련 문제