4

数据库有一个transactions包含列的表:account_id, date, transaction_value(有符号整数)。account_value另一个表transaction_value(它使用transactions表上的触发器进行更新(即,INSERT、UPDATE 和 DELETEtransactions触发触发器以更改account_value.)

一项新要求是仅计算帐户在过去 365 天内的总交易价值。只需要当前的运行总计,而不是以前的总计。将经常请求此值,几乎与account_value.

你将如何有效地实现这个“滑动窗口总和”?一个新的表是好的。有没有办法避免每次对一年的范围求和?

4

5 回答 5

2

这可以通过标准的窗口函数来完成:

SELECT account_id,
       sum(transaction_value) over (partition by account_id order by date)
FROM transactions

条款的order by内部over()使总和成为“滑动总和”。

对于“仅过去 356 天”,您需要第二个查询来限制 WHERE 子句中的行。

以上适用于 PostgreSQL、Oracle、DB2 和(我认为)Teradata。SQL Server 不支持窗口定义中的 order by(即将推出的 Denali 版本将 AFAIK)

于 2012-01-13T09:45:38.247 回答
1

如果对事务表的查询比对事务表的插入更频繁,那么也许视图是要走的路?

于 2012-01-13T09:40:43.533 回答
1

就这么简单?

SELECT
   SUM(transaction_value), account_id
FROM
   transactions t
WHERE
   -- SQL Server, Sybase       t.DATE >= DATEADD(year, -1, GETDATE())
   -- MySQL            t.DATE >= DATE_SUB(NOW(), INTERVAL 12 MONTH)
GROUP BY
   account_id;

您可能希望使用 DATE (MySQL) 或在 SQL Server 中以这种方式从日期表达式中删除时间组件

于 2012-01-13T09:31:18.483 回答
0

您将需要一个一次性脚本来为现有表填充每条现有记录的前一年的值 - 对于生成的每条记录,该脚本需要在整个上一年运行。

填充滚动年份列后,对上一年求和的一种替代方法是将每个新记录的值作为上一个记录的滚动年份值,加上自上次更新以来的交易价值,减去一年之间的交易价值在上次更新之前和一年前从现在开始。

我建议针对实际的测试数据尝试这两种方法,看看哪一种表现更好——我希望在数据相对稀疏的情况下,对全年的总和至少表现得一样好,而如果要经常更新数据,差异方法可能会更好每个帐户。

于 2012-01-13T09:41:49.667 回答
0

我将在这里避免任何实际的 SQL,因为它会根据您使用的 SQL 的种类而变化很大。


你说你有一个触发器来维持现有的运行总计。

我认为它也(或者可能是每晚的过程)在account_value表中创建新的每日记录。然后 INSERTs、UPDATEs 和 DELETEs 触发触发器以从现有的运行总数中添加或减去?

您需要做的唯一更改是:
- 添加一个新字段,“yearly_value”或其他内容
- 以与现有字段相同的方式更新现有触发器
- 使用 gbn 的答案类型来创建今天的记录(或者无论您有多远回溯)
- 但以稍微不同的方式初始化每个新的每日记录......

当您为新的一天插入新行时,应将其初始化为yesterday's value- the value 365 days ago。之后,行为应该与您已经习惯的行为相同。

于 2012-01-13T09:42:05.323 回答