处理交易表中的到期信用?

时间:2016-04-25 04:43:59

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

考虑表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

如果没有到期处理,要获得当前用户数量,可以通过简单的选择处理

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

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

目前..

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

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

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

4 个答案:

答案 0 :(得分:1)

当您使用否定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

答案 1 :(得分:1)

这里有一些设计陷阱。如果某人的信用额度在不同日期到期,则需要某种逻辑来准确计算出哪些信用额被消费 - 这很重要,因为到期时可能会产生不同的余额结果,具体取决于所选择的信用额度。如果可以退还支出,这就变得更加混乱。

因此,我建议将其分为两个表格。我也冒昧地在没有NOT NULL的情况下创建了一些字段DEFAULT - 也就是说,强制它们在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为空的信用额可能是余额。

请注意,Credits行不应以除设置SinkTransactionID之外的任何方式更新,因此不能被多个事务中的每一个部分消耗 - 而是仅想要下沉的事务Credits行的一部分需要在部分使用的行上插入包含“更改”的新Credits行,并将其自身引用为源。

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

答案 2 :(得分:0)

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.

答案 3 :(得分:0)

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