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 

일년 중 매일 몇 가지 항목이 포함되어 있으며 5 일마다 잔액을 가져 오려고합니다. 나는 또한 계정간에 분리하기를 원한다. (즉, 두번의 변경이 같은 날에 발생하였으나 별도의 계정에서는 두 가지 모두를 리턴한다.)

문제는 다음과 같습니다. : 경우에 따라 며칠 (또는 몇 주) 동안 사용할 수있는 데이터가 없습니다. 이 경우 데이터 세트의 "구멍"인 앞에이라는 최신 항목을 반환해야합니다. 이것은 문제의 단순화 된 버전이며, 실제 데이터베이스는 크고 (수 기가 바이트) 크기 때문에 데이터의 서브 세트를 반환하려는 이유가 있습니다. 그것은 오라클과 mySQL 모두에서 작동해야하기 때문에 플랫폼 특정 메소드를 사용할 수 없습니다.

내 질문은입니다.이 작업을 수행 할 방법이 있습니까? ? 작업을 완료하는 쿼리를 작성할 수 있지만 중첩 된 쿼리 및 집계 함수를 많이 필요로하지 않는 일부 악마 마법 방법이 필요합니다.

답변

2

Andomar의 기간 테이블 아이디어를 사용 하겠지만 약간 다른 최종 쿼리를 시도합니다. 여기서는 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이 내 것보다 낫습니다. "별개의 보조 기능"을 수행하지 않고 공동 참여가 더 빠를 수도 있습니다. 내 검색어를 바꿀 수 있습니까? – Andomar

+0

@Andomar : 그래, 자유롭게. 때로는 데이터에 따라 한 가지 방법이 다른 것보다 더 빠를 수도 있지만. 대부분의 경우 LEFT OUTER JOIN이 더 빠르다고 느낍니다. –

+0

고마워요, 편집 됨. 같은 날짜의 잔액이 여러 개 있기 때문에 테스트 데이터가 작동하지 않는 날짜 확인이 필요합니다. – Andomar

1

당신은 비교적 간단한 방법으로이 작업을 수행 할 수있는 기능 할 수있을 것 기간 당 계정 당 행.

다음은 예입니다. 의 일부 임시 테이블을 설정하자

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 

각 균형을 하나 개의 행을 추가하기

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

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

는 몇 가지 테스트 데이터를 입력 기간 :

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 

B2를은 기본적으로 "그 사이"값을 찾습니다, 그것은 아이디가 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"로 바꿀 수 있습니다.

관련 문제