0

我有一个带有表的数据库,用于存储跨几个帐户的帐户余额更改,其中包含三列;

float   balance, #The account balance after the change
Date    date,    #Date that balance change occurred
int     aid      #Account that the balance change occurred on

它包含一年中每一天的几个条目,我想检索每五天的余额。我还希望它在帐户之间分开(即,如果在同一天发生了两次更改,但在不同的帐户上,则两者都返回)。

问题是这样的:有时会有几天(或几周)没有可用数据。发生这种情况时,我想确保在数据集中的“洞”之前返回最新条目。这是问题的简化版本,实际数据库很大(几千兆字节),大小是我要返回数据子集的原因。它不能使用特定于平台的方法,因为它需要同时在 oracle 和 mySQL 上工作。

我的问题是:有什么方法可以快速做到这一点?我将能够编写一个完成工作的查询,但我希望有一些不需要大量嵌套查询和聚合函数的魔鬼魔法方式。

4

3 回答 3

2

我会使用 Andomar 的 Period table 想法,但我会尝试稍微不同的最终查询。这假设您的 Account_Balances 表具有援助和日期的 PK。如果您最终在相同的确切日期和时间为同一帐户获得了两个余额,那么您会得到一些重复的行。

SELECT
     P.start_date,
     P.end_date,
     AB1.account_id,
     AB1.balance
FROM
     Periods P
LEFT OUTER JOIN Account_Balances AB1 ON
     AB1.date <= P.end_date
LEFT OUTER JOIN Account_Balances AB2 ON
     AB2.aid = AB1.aid AND
     AB2.date > AB1.date AND
     AB2.date <= P.end_date
WHERE
     AB2.aid IS NULL

如果该帐户在给定期间之前或期间没有任何行,您将不会得到它的行。

于 2009-04-24T14:22:41.423 回答
1

您可以通过创建一个周期表以相对简单的方式执行此操作,您可以将其与帐户表连接以在每个帐户每个周期创建一行。

这是一个例子。让我们设置一些临时表:

create table #balance (
    id int identity,
    balance float,
    date datetime,
    aid int
)

create table #period (
    id int identity,
    startdt datetime,
    enddt datetime
)

输入一些测试数据:

insert into #yourtable (balance, date, aid) values (4,'2009-01-01',1)
insert into #yourtable (balance, date, aid) values (5,'2009-01-10',1)
insert into #yourtable (balance, date, aid) values (6,'2009-01-10',1)
insert into #yourtable (balance, date, aid) values (7,'2009-01-16',1)
insert into #yourtable (balance, date, aid) values (2,'2009-01-01',2)
insert into #yourtable (balance, date, aid) values (3,'2009-01-10',2)
insert into #yourtable (balance, date, aid) values (4,'2009-01-10',2)
insert into #yourtable (balance, date, aid) values (5,'2009-01-16',2)

insert into #period (startdt, enddt) values ('2009-01-01','2009-01-06')
insert into #period (startdt, enddt) values ('2009-01-06','2009-01-11')
insert into #period (startdt, enddt) values ('2009-01-11','2009-01-16')
insert into #period (startdt, enddt) values ('2009-01-16','2009-01-21')

现在让我们查询所有时期:

from #period p

在期末前为每个余额添加一行:

left join #balance b1 on 
    b1.date <= p.enddt

在第一次加入的余额和期末之间搜索余额:

left join #balance b2 on 
    b2.aid = b1.aid
    and b1.id < b2.id
    and b2.date <= p.enddt

然后过滤掉不是其期间最后余额的行。

where
    b2.aid is null

b2 连接基本上寻找“中间”值,并且通过说它的 id 为空,你说不存在中间行。最终查询如下所示:

select 
    b1.aid
,   p.startdt
,   b1.balance
from #period p
left join #balance b1 on 
    b1.date <= p.enddt
left join #balance b2 on 
    b2.aid = b1.aid
    and b1.id < b2.id
    and b2.date <= p.enddt
where
    b2.aid is null
order by b1.aid, p.startdt

注意:查询假设余额与较晚的日期总是有较大的 id。如果您不必使用完全相同的结束日期进行余额,则可以将“b1.id < b2.id”替换为“b1.date < b2.date”。

于 2009-04-24T10:11:18.767 回答
0

如果您等待 postgresql 8.4,您也许可以使用窗口函数

http://www.postgresql.org/docs/8.4/static/tutorial-window.html

http://www.postgresql.org/docs/8.4/static/functions-window.html

于 2009-04-24T09:48:17.217 回答