考虑表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,并且能够获得当时可用的信用额度,如下所示..
目前..
仅使用上述架构是否可行?或者我需要添加额外的字段?
SQLFiddle:http://sqlfiddle.com/#!9/3a52b/3
答案 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