2009-04-24 5 views
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.

Мой вопрос:: Есть ли способ сделать это fast? Я бы мог написать запрос, который выполняет эту работу, но я надеюсь, что есть какой-то магический способ дьявола, который не требует много вложенных запросов и агрегатных функций.

ответ

2

Я бы использовал идею таблицы периода Андомара, но я попробую несколько другой окончательный запрос. Это предполагает, что в таблице 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 

Если учетная запись не имеет строк до или в течение заданного периода, вы не получите строку для нее.

+0

ool, выглядит лучше, чем у меня: вы не выполняете «отличную помощь», а соединение noone-in-between, вероятно, быстрее. Это нормально, если я изменю свой запрос на основе вашего? – Andomar

+0

@Andomar: Да, не стесняйтесь. Хотя иногда один метод может быть быстрее другого, в зависимости от данных. В большинстве случаев я нахожу, что LEFT OUTER JOIN быстрее. –

+0

Спасибо, отредактирован. Исследуйте проверку даты, которая не работает для тестовых данных, поскольку она имеет несколько балансов с той же датой. – Andomar

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 

Море RCH для противовесов между ними баланс от первого соединения, и конец периода:

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

Затем отфильтровать строки, которые не последний баланс за период.

where 
    b2.aid is null 

Б2 присоединиться в основном выглядит для «в-между» значением, и, говоря это идентификатор является недействительным, вы говорите, нет в промежутке между строками существуют. Окончательный запрос выглядит так:

Примечание: запросы принимают баланс с более поздней датой, всегда имеют более высокий идентификатор.Если вам никогда не приходилось балансировать с точно такой же конечной датой, вы можете заменить «b1.id < b2.id» на «b1.date < b2.date».