Selecionando intervalos de data, fazê-lo rápido, e sempre retornando a entrada mais recente com o resultado
-
16-09-2019 - |
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 ..
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