0

私はテーブルを持つデータベースを持っており、いくつかのアカウントの口座残高の変化を 3 つの列で保存しています。

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

1 年の各日についていくつかのエントリが含まれており、5 日ごとに残高を取得したいと考えています。また、アカウント間で分離したい (つまり、2 つの変更が同じ日に発生したが、別のアカウントで発生した場合は、両方を返す)。

問題は次のとおりです。データが利用できない場合が数日 (または数週間) ある場合があります。その場合、データセットの「穴」のに最新のエントリを返すようにします。これは問題の単純化されたバージョンです。実際のデータベースは大きい (数ギガバイト) ため、データのサブセットを返したい理由はそのサイズです。Oracle と MySQL の両方で動作する必要があるため、プラットフォーム固有のメソッドを使用することはできません。

私の質問は次のとおりです。これをすばやく行う方法はありますか? 仕事を終わらせるクエリを書くことはできますが、多くのネストされたクエリと集計関数を必要としない悪魔の魔法の方法があることを願っています..

4

3 に答える 3

2

Andomarの周期表のアイデアを使用しますが、少し異なる最終的なクエリを試します。これは、Account_Balancesテーブルに援助と日付のPKがあることを前提としています。同じ正確な日時の同じアカウントに対して2つの残高が発生した場合、重複する行がいくつか取得されます。

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

これは、期間テーブルを作成することで比較的簡単な方法で行うことができます。期間テーブルをアカウントテーブルと結合して、期間ごとにアカウントごとに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

期間が終了する前に、残高ごとに1行を追加します。

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がnullであると言うことで、中間行が存在しないことを示します。最終的なクエリは次のようになります。

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 に答える