我在信用表中
((id,user_id,进程,金额,date_add,date_exp,date_redeemed,备注)
SELECT * FROM credits WHERE user_id = 2;
+----+---------+---------+--------+------------+------------+---------------+----------+
| id | user_id | process | amount | date_add | date_exp | date_redeemed | remark |
+----+---------+---------+--------+------------+------------+---------------+----------+
| 22 | 2 | Add | 200.00 | 2018-01-01 | 2019-01-01 | | Credit1 |
| 23 | 2 | Add | 200.00 | 2018-03-31 | 2019-03-31 | | Credit2 |
| 24 | 2 | Deduct | 200.00 | | | 2018-04-28 | Redeemed |
| 25 | 2 | Add | 200.00 | 2018-07-11 | 2018-10-11 | | Campaign |
| 26 | 2 | Deduct | 50.00 | | | 2018-08-30 | Redeemed |
| 27 | 2 | Add | 200.00 | 2018-10-01 | 2019-09-30 | | Credit3 |
| 28 | 2 | Deduct | 198.55 | | | 2018-10-20 | Redeemed |
+----+---------+---------+--------+------------+------------+---------------+----------+
我写的以下查询将仅计算余额,但我不知道信用额是否已到期并在到期前使用。
SELECT
u.id,
email,
CONCAT(first_name, ' ', last_name) AS name,
type,
(CASE
WHEN (SUM(amount) IS NULL) THEN 0.00
ELSE CASE
WHEN
(SUM(CASE
WHEN process = 'Add' THEN amount
END) - SUM(CASE
WHEN process = 'Deduct' THEN amount
END)) IS NULL
THEN
SUM(CASE
WHEN process = 'Add' THEN amount
END)
ELSE SUM(CASE
WHEN process = 'Add' THEN amount
END) - SUM(CASE
WHEN process = 'Deduct' THEN amount
END)
END
END) AS balance
FROM
users u
LEFT JOIN
credits c ON u.id = c.user_id
GROUP BY u.id;
还是我做错了方法?也许我应该在后端而不是在SQL中进行计算?
编辑1:
我想计算每个用户的电子钱包的余额,但是信用会过期,
如果它已过期且未兑换,则从余额中排除
在到期前使用ELSE IF,并兑换金额<到期金额 然后(余额-(到期金额-赎回金额))
在到期前使用ELSE IF和赎回金额>到期金额 然后,将使用可用余额扣除,因为到期金额不足以扣除已兑换的金额
编辑2:
上面的查询将输出351.45,我的预期输出是201.45。由于赎回金额低于到期金额,因此无法计算2018-08-30的赎回金额
编辑3:
用户表:
+----+------------+-----------+----------+----------------+----------+
| id | first_name | last_name | type | email | password |
+----+------------+-----------+----------+----------------+----------+
| 2 | Test | Oyster | Employee | test@gmail.com | NULL |
+----+------------+-----------+----------+----------------+----------+
我的输出:
+----+----------------+-------------+----------+---------+
| id | email | name | type | balance |
+----+----------------+-------------+----------+---------+
| 2 | test@gmail.com | Test Oyster | Employee | 351.45 |
+----+----------------+-------------+----------+---------+
预期输出:
总(200 + 200 + 200)600
兑现金额448.55(200 + 50 + 198.55)
剩余余额为151.45
+----+----------------+-------------+----------+---------+
| id | email | name | type | balance |
+----+----------------+-------------+----------+---------+
| 2 | test@gmail.com | Test Oyster | Employee | 151.45 |
+----+----------------+-------------+----------+---------+
答案 0 :(得分:5)
当前表存在一些基本的结构性问题。因此,我将对表结构和随后的应用程序代码提出一些更改。电子钱包系统的表格结构非常详细;但我建议在此进行最小程度的更改。 我并不是说这是理想的方法。但应该可以。最初,我将介绍当前方法的一些问题。
问题:
常规做法:
我们通常采用 FIFO (先进先出)方法,以使客户获得最大利益。因此,较早使用的信用额度(没有使用权的情况下更有可能过期)。
为了遵循FIFO,我们必须每次都在查询/应用程序代码中有效使用循环技术,以计算基本内容,例如“可用的钱包余额”,“过期的和未充分利用的信用”等等。为此编写查询将很麻烦,并且在更大范围内可能效率低下
解决方案:
我们可以在当前表中再添加一列amount_redeemed
。它基本上代表针对特定信用额的已兑现的金额。
ALTER TABLE credits ADD COLUMN amount_redeemed DECIMAL (8,2);
因此,已填充的表格如下所示:
+----+---------+---------+--------+-----------------+------------+---------------+---------------+----------+
| id | user_id | process | amount | amount_redeemed | date_add | date_exp | date_redeemed | remark |
+----+---------+---------+--------+-----------------+------------+---------------+---------------+----------+
| 22 | 2 | Add | 200.00 | 200.00 | 2018-01-01 | 2019-01-01 | | Credit1 |
| 23 | 2 | Add | 200.00 | 200.00 | 2018-03-31 | 2019-03-31 | | Credit2 |
| 24 | 2 | Deduct | 200.00 | | | | 2018-04-28 | Redeemed |
| 25 | 2 | Add | 200.00 | 0.00 | 2018-07-11 | 2018-10-11 | | Campaign |
| 26 | 2 | Deduct | 50.00 | | | | 2018-08-30 | Redeemed |
| 27 | 2 | Add | 200.00 | 48.55 | 2018-10-01 | 2019-09-30 | | Credit3 |
| 28 | 2 | Deduct | 198.55 | | | | 2018-10-20 | Redeemed |
+----+---------+---------+--------+-----------------+------------+---------------+---------------+----------+
请注意,使用FIFO方法,针对amount_redeemed
的信用的id = 25
为 0.00 。它有机会在2018-10-20
上进行兑换,但是到那时,它已经过期(date_exp = 2018-10-11
)
因此,现在完成此设置后,您就可以在应用程序代码中执行以下操作:
amount_redeemed
值:这将是一次活动。为此,制定单个查询将很困难(这就是为什么我们首先出现在这里)。因此,我建议您使用循环和FIFO方法在应用程序代码(例如PHP)中执行一次。查看下面的第3点,以了解如何在应用程序代码中进行操作。
现在查询变得无关紧要了,因为我们只需要为尚未到期的所有amount - amount_redeemed
进程计算Add
的总和即可。
SELECT SUM(amount - amount_redeemed) AS total_available_credit
FROM credits
WHERE process = 'Add' AND
date_exp > CURDATE() AND
user_id = 2
amount_redeemed
:在这种情况下,您首先可以获取所有可用的点数,这些点数可以兑换,并且尚未过期。
SELECT id, (amount - amount_redeemed) AS available_credit
FROM credits
WHERE process = 'Add' AND
date_exp > CURDATE() AND
user_id = 2 AND
amount - amount_redeemed > 0
ORDER BY id
现在,我们可以遍历以上查询结果,并相应地利用金额
// PHP code example
// amount to redeem
$amount_to_redeem = 100;
// Map storing amount_redeemed against id
$amount_redeemed_map = array();
foreach ($rows as $row) {
// Calculate the amount that can be used against a specific credit
// It will be the minimum of available credit and amount left to redeem
$amount_redeemed = min($row['available_credit'], $amount_to_redeem);
// Populate the map
$amount_redeemed_map[$row['id']] = $amount_redeemed;
// Adjust the amount_to_redeem
$amount_to_redeem -= $amount_redeemed;
// If no more amount_to_redeem, we can finish the loop
if ($amount_to_redeem == 0) {
break;
} elseif ($amount_to_redeem < 0) {
// This should never happen, still if it happens, throw error
throw new Exception ("Something wrong with logic!");
exit();
}
// if we are here, that means some more amount left to redeem
}
现在,您可以使用两个更新查询。第一个将针对所有信用ID更新amount_redeemed
值。第二个将使用所有单独的Insert
值的总和来amount_redeemed
扣除行。
答案 1 :(得分:3)
SELECT `id`, `email`, `NAME`, `type`,
(
( SELECT SUM(amount) FROM credit_table AS ct1 WHERE u.id = ct1.id AND process = 'ADD' AND date_exp > CURDATE()) -
( SELECT SUM(amount) FROM credit_table AS ct2 WHERE u.id = ct2.id AND process = 'Deduct' )
) AS balance
FROM
`user_table` AS u
WHERE
id = 2;
希望它如您所愿