【问题标题】:Handle expiry credits in a transaction table?处理交易表中的到期信用?
【发布时间】:2016-08-18 08:19:12
【问题描述】:

考虑表Credits

 CREATE TABLE `Credits` (
  `UserID` int(11) unsigned NOT NULL DEFAULT '0',
  `Amount` int(11) NOT NULL DEFAULT '0',
  `Created` datetime NOT NULL DEFAULT '0000-00-00 00:00:00',
  `Expire` datetime NOT NULL DEFAULT '9999-12-31 23:59:59'
) 

有数据:

UserID    Amount    Created       Expire
1         10        2016-01-14    2016-05-30
1         -2        2016-02-04    9999-12-31
1         3         2016-06-01    2016-09-30

没有Expiry处理,获取当前用户的数量,可以通过简单的select来处理

 SELECT SUM(Amount) FROM Credits WHERE UserID = 1;

现在,我需要编写一个 SELECT 查询,输入参数为日期,并且能够获得当时可用的积分,如下所示..

在..

  • 2016-01-15 => 10
  • 2016-02-06 => 8
  • 2016-05-31 => 0
  • 2016-06-03 => 3

是否可以仅使用上述架构?或者我需要添加额外的字段?

SQLFiddle:http://sqlfiddle.com/#!9/3a52b/3

【问题讨论】:

  • 请显示进行更新的代码。请在帮助中心阅读有关 MCVE 的信息。
  • 这里有一个设计陷阱。如果某人的积分在不同日期到期,您需要某种逻辑来准确计算出消耗了哪些积分 - 这很重要,因为到期可能会根据选择的积分产生不同的余额结果。如果支出可以退还,那就更麻烦了。
  • @JeffreyHantin,你是对的,所以对于这个问题,我也在寻找可以做任何设计改进..
  • @Ryan,我已经添加了答案。

标签: mysql sql database database-design database-schema


【解决方案1】:
SELECT SUM(t.Amount) 
from (select case amount 
             when current_date>expiry_date then 1
             else 0
             end as amount
      FROM Credits WHERE UserID = 1 AND Expire <= CURDATE()
     )t.

【讨论】:

  • 感谢您的评论。我已经用更详细的说明和 4 个测试用例更新了我的问题,你能重新访问它吗?谢谢
【解决方案2】:
SELECT 
CASE WHEN SUM(c.amount) > 0 then SUM(c.amount) else 0 end as total_amount
FROM Credits c 
where c.userId = 1 and c.Expire <= CURDATE() -- or any date

Sqlfiddle demo.

【讨论】:

  • 感谢您的评论。我已经用更详细的说明和 4 个测试用例更新了我的问题,你能重新访问它吗?谢谢
【解决方案3】:

当您与负Amount进行交易时,您应该找到与正Amount对应的交易并设置相同的到期日期。这样,您就可以存储您花费的积分的到期日期。您的示例表将如下所示:

UserID    Amount    Created       Expire
1         10        2016-01-14    2016-05-30
1         -2        2016-02-04    2016-05-30
1         3         2016-06-01    2016-09-30

这使得查询任何特定日期的余额如下所示:

SELECT SUM(Amount) FROM Credits WHERE UserID = 1 and @date between Created and Expire;

请注意,您可能必须拆分一笔金额为负的交易以支付不同到期日期的信用额度。例如,您有下表:

UserID    Amount    Created       Expire
1         10        2016-01-14    2016-05-30
1         10        2016-02-04    2016-06-30

如果你想和Amount=-15进行交易,那么你需要做两条记录:

UserID    Amount    Created       Expire
1         -10       2016-04-26    2016-05-30
1         -5        2016-04-26    2016-06-30

要找出尚未使用或已过期的积分及其到期日期,您可以使用以下查询:

select sum(Amount) as Amount, Expire
from Credits
where UserID = 1 and curdate() <= Expire
group by Expire
having sum(Amount) > 0
order by Expire

【讨论】:

  • 谢谢,如果需要花费的金额不是-15,而是5,例如?只花费了部分正积分..
  • @Ryan 然后,假设您想先花掉过期的积分,您可以创建一条记录UserID=1, Amount=-5, Created=2016-04-26, Expire=2016-05-30
【解决方案4】:

这里有一个设计陷阱。如果某人的积分在不同日期到期,您需要某种逻辑来准确计算出消耗了哪些积分 - 这很重要,因为到期可能会根据选择的积分产生不同的余额结果。如果支出可以退还,那就更麻烦了。

因此,我建议将其分成两个表。我还冒昧地在不带DEFAULT 的情况下创建了一些字段NOT NULL - 也就是说,强制它们在INSERT 上提供 - 并且为了清楚起见删除了标识符引用。

CREATE TABLE Transactions (
  TransactionID int(11) unsigned NOT NULL AUTO_INCREMENT,
  Timestamp datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
  Caption nvarchar(50) NOT NULL,
  PRIMARY KEY (TransactionID)
)

CREATE TABLE Credits (
  UserID int(11) unsigned NOT NULL,
  Amount int(11) NOT NULL,
  Expire datetime NOT NULL DEFAULT '9999-12-31 23:59:59',
  ProducingTransactionID int(11) unsigned NOT NULL REFERENCES ,
  ConsumingTransactionID int(11) unsigned NULL,
  PRIMARY KEY (UserID, Amount, Expire, ProducingTransaction),
  INDEX (UserID, ConsumingTransaction, Expire),
  FOREIGN KEY (SourceTransactionID) REFERENCES Transactions (TransactionID),
  FOREIGN KEY (SinkTransactionID) REFERENCES Transactions (TransactionID),
)

这里的想法是强制交易明确说明它们正在影响哪些信用,并记录这些明确的选择。如果没有指向它们来源的SourceTransactionID 的链接,则无法添加积分;使用积分时,SinkTransactionID 会简单地填充指向使用它们的交易的链接,并且只有 SinkTransactionID 为空的积分才是潜在可用余额。

请注意,除了设置SinkTransactionID 之外,不应以任何方式更新Credits 行,因此不能由多个事务中的每一个事务部分使用 - 相反,只想接收部分@ 的事务987654329@ 行需要插入一个新的Credits 行,其中包含部分使用的行上的“更改”并将其自身作为源引用。

时间点余额查询变得稍微复杂一些,因为现在您必须加入 Transactions 以过滤掉在预期时间点之后发生的交易。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2012-07-29
    • 2020-07-23
    • 2014-12-22
    • 2017-07-15
    • 1970-01-01
    • 2011-08-12
    • 2014-11-06
    • 2016-03-24
    相关资源
    最近更新 更多