Selecionando intervalos de data, fazê-lo rápido, e sempre retornando a entrada mais recente com o resultado

StackOverflow https://stackoverflow.com/questions/785172

Pergunta

Eu tenho um banco de dados com uma tabela, armazenando mudanças na conta de balanço através de um par de contas, com três colunas;

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

Ele contém um par de entradas para cada dia do ano, e eu quero recuperar o equilíbrio de cada cinco dias. Eu também quero isso para separar entre contas (ou seja, se duas mudanças ocorreu no mesmo dia, mas em contas separadas, retornar ambos).

O problema é este : Às vezes, haverá vários dias (ou semanas) onde não há dados disponíveis. Quando isso ocorre, eu quero ter a certeza de voltar a entrada mais recente antes o "buraco" no conjunto de dados. Esta é uma versão simplificada do problema, o banco de dados real é grande (vários gigabytes), o tamanho é a razão pela qual eu quero retornar um subconjunto dos dados. Ele não pode usar métodos plataforma específica, porque ele precisa trabalhar em Oracle e mySQL.

A minha pergunta é : Existe alguma maneira de fazer isso rápido ? Eu seria capaz de escrever uma consulta que começa o trabalho feito, mas estou esperando há alguma maneira diabo magia de fazê-lo que não requer muitas consultas aninhadas e funções agregadas ..

Foi útil?

Solução

Gostaria de usar ideia mesa Período de Andomar, mas eu gostaria de tentar uma consulta final ligeiramente diferente. Isso pressupõe que sua tabela Account_Balances tem um PK da ajuda ea data. Se você acabou com dois saldos para a mesma conta a mesma data e hora exata para, em seguida, você iria obter algumas linhas duplicadas.

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

Se a conta não tem linhas antes ou durante o período determinado você não vai obter uma fileira traseira para ele.

Outras dicas

Você pode fazer isso de uma maneira relativamente simples, criando uma tabela período, o que você pode juntar-se com a tabela de contas para criar uma linha por conta por período.

Aqui está um exemplo. Vamos definir algumas tabelas temporárias:

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

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

Entre alguns dados de teste:

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')

Agora vamos consultar todos os períodos:

from #period p

Adicionar uma linha para cada equilíbrio antes do final do período:

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

Procure saldos entre o balanço do primeiro unir-se, e no final do período:

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

Em seguida, filtrar as linhas que não estão no último balanço para o seu período.

where
    b2.aid is null

O b2 juntar-se, basicamente, procura o "entre" valor, e dizendo que é id é nulo, você diz que não in-between existe linha. Os olhares consulta final como este:

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

Nota: as consultas assumir um equilíbrio com uma data posterior sempre tem um ID maior. Se você nunca tem que saldos com exatamente a mesma data de término, você pode substituir "b1.id

Se você esperar para o PostgreSQL 8.4 você pode ser capaz de fazer uso de funções da janela

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

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

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top