이전 응답의 샘플 데이터 사용 :
create table t1 (
AssetID varchar(10),
LocationID varchar(10),
SublocationID varchar(10),
MoveDate datetime
);
insert into t1
select 'CAR1', 'LOC1', 'SUB1', '1/1/2015 01:01:01' union all
select 'CAR1', 'LOC1', 'SUB2', '1/3/2015 03:03:03' union all
select 'CAR1', 'LOC1', 'SUB1', '1/4/2015 04:04:04' union all
select 'CAR1', 'LOC99', 'SUB99', '1/5/2015 05:05:05' union all
select 'CAR1', 'LOC1', 'SUB1' , '1/9/2015 09:09:09' union all
select 'CAR2', 'LOC1', 'SUB1', '1/1/2015 01:01:01' union all
select 'CAR2', 'LOC1', 'SUB2', '1/3/2015 03:03:03' union all
select 'CAR2', 'LOC1', 'SUB1', '1/4/2015 04:04:04' union all
select 'CAR2', 'LOC99', 'SUB99', '1/5/2015 05:05:05' union all
select 'CAR2', 'LOC1', 'SUB1' , '1/9/2015 09:09:09';
select * from t1;
╔═════════╦════════════╦═══════════════╦════════════════════════════════╗
║ ASSETID ║ LOCATIONID ║ SUBLOCATIONID ║ MOVEDATE ║
╠═════════╬════════════╬═══════════════╬════════════════════════════════╣
║ CAR1 ║ LOC1 ║ SUB1 ║ January, 01 2015 01:01:01+0000 ║
║ CAR2 ║ LOC1 ║ SUB1 ║ January, 01 2015 01:01:01+0000 ║
║ CAR2 ║ LOC1 ║ SUB2 ║ January, 03 2015 03:03:03+0000 ║
║ CAR1 ║ LOC1 ║ SUB2 ║ January, 03 2015 03:03:03+0000 ║
║ CAR1 ║ LOC1 ║ SUB1 ║ January, 04 2015 04:04:04+0000 ║
║ CAR2 ║ LOC1 ║ SUB1 ║ January, 04 2015 04:04:04+0000 ║
║ CAR2 ║ LOC99 ║ SUB99 ║ January, 05 2015 05:05:05+0000 ║
║ CAR1 ║ LOC99 ║ SUB99 ║ January, 05 2015 05:05:05+0000 ║
║ CAR1 ║ LOC1 ║ SUB1 ║ January, 09 2015 09:09:09+0000 ║
║ CAR2 ║ LOC1 ║ SUB1 ║ January, 09 2015 09:09:09+0000 ║
╚═════════╩════════════╩═══════════════╩════════════════════════════════╝
리드() 분석 기능이 지원되는 경우, (단순성과 성능면에서 모두) 바람직한 해결책은 다음과 같습니다
select AssetID, LocationID,
sum(datediff(dd,MoveDate,isnull(nextMoveDate,getDate()))) daysAtLoc
from (
select AssetID, LocationID, MoveDate,
lead(MoveDate) over (partition by AssetID
order by MoveDate) nextMoveDate
from t1
) t2
group by AssetID, LocationID
order by AssetID, LocationID;
╔═════════╦════════════╦═══════════╗
║ ASSETID ║ LOCATIONID ║ DAYSATLOC ║
╠═════════╬════════════╬═══════════╣
║ CAR1 ║ LOC1 ║ 18 ║
║ CAR1 ║ LOC99 ║ 4 ║
║ CAR2 ║ LOC1 ║ 18 ║
║ CAR2 ║ LOC99 ║ 4 ║
╚═════════╩════════════╩═══════════╝
순수한 SQL 솔루션 : 어떤 분석, 아니 재귀 CTE, 더 OUTER가 적용되지 않습니다/correlated-subqueries; 단순한 조인. 나는 Azure-SQL으로 일한 적이 없지만, 이것이 지원되지 않는다면 (또한 여전히 SQL이라고 불린다) 꽤 놀랄 것이다.
select AssetID, LocationID,
sum(datediff(dd,MoveDate,isnull(nextMoveDate,getdate()))) daysAtLoc
from (
select t1.AssetID, LocationID, MoveDate,
min(nextMoveDate) nextMoveDate
from t1
left outer join
(select AssetID, MoveDate nextMoveDate
from t1) n
on t1.AssetId = n.AssetID
and MoveDate < nextMoveDate)
group by t1.AssetID, LocationID, MoveDate
) t2
group by AssetID, LocationID
order by AssetID, LocationID
╔═════════╦════════════╦═══════════╗
║ ASSETID ║ LOCATIONID ║ DAYSATLOC ║
╠═════════╬════════════╬═══════════╣
║ CAR1 ║ LOC1 ║ 18 ║
║ CAR1 ║ LOC99 ║ 4 ║
║ CAR2 ║ LOC1 ║ 18 ║
║ CAR2 ║ LOC99 ║ 4 ║
╚═════════╩════════════╩═══════════╝
성능 경고 - n은 자산 당 최대 이동 수이고, m은 자산 수입니다. 분석 함수 버전은 m * (n log n)의 Big-O 성능을 가져야합니다. pure-SQL 버전은 Big *가 m * (n * n)이어야합니다.따라서 일정한 자산 풀을 추적하면서 시간이 지남에 따라 움직임이 점점 더 많아지면 (자산 당 이동 수가 꾸준히 증가하게 됨) 쿼리가 기하 급수적으로 느려집니다. 오랜 기간 동안 쿼리를 수행하고 개별 자산에 대해 수십 또는 수천 개의 동작을 기록하는 경우 월간 배치로 계산 한 다음 그 결과를 합산해야 할 수 있습니다. 즉, 엄청난 양의 자산이 있고 각 인스턴스의 움직임이 상대적으로 적다면 pure-SQL 버전은 Analytic Function 버전과 함께 수행해야합니다.
- EDIT 1 : 오리지널 SQL 용액에 고정 오타 (추가 괄호)
- EDIT 2 일자 범위를 지원할 용액 확장이 - 또한 용액의 안정성을 확인하기 위해 입력 데이터를 조금 불통.
create table t1 (
AssetID varchar(10),
LocationID varchar(10),
SublocationID varchar(10),
MoveDate datetime,
primary key (AssetId, MoveDate));
insert into t1
select 'CAR1', 'LOC1', 'SUB1', '01/01/2015 00:00:00' union
select 'CAR1', 'LOC1', 'SUB2', '01/03/2015 03:03:03' union
select 'CAR1', 'LOC1', 'SUB1', '01/04/2015 04:04:04' union
select 'CAR1', 'LOC99', 'SUB99', '01/05/2015 05:05:05' union
select 'CAR1', 'LOC1', 'SUB1' , '01/09/2015 09:09:09' union
select 'CAR2', 'LOC1', 'SUB2', '01/03/2015 03:03:03' union
select 'CAR2', 'LOC1', 'SUB1', '01/04/2015 04:04:04' union
select 'CAR2', 'LOC99', 'SUB99', '01/05/2015 05:05:05' union
select 'CAR2', 'LOC1', 'SUB1' , '01/09/2015 09:09:09' union
select 'CAR3', 'LOC2', 'SUB1' , '01/15/2015 15:15:15'
;
╔═════════╦════════════╦═══════════════╦════════════════════════════════╗
║ ASSETID ║ LOCATIONID ║ SUBLOCATIONID ║ MOVEDATE ║
╠═════════╬════════════╬═══════════════╬════════════════════════════════╣
║ CAR1 ║ LOC1 ║ SUB1 ║ January, 01 2015 00:00:00+0000 ║
║ CAR1 ║ LOC1 ║ SUB2 ║ January, 03 2015 03:03:03+0000 ║
║ CAR1 ║ LOC1 ║ SUB1 ║ January, 04 2015 04:04:04+0000 ║
║ CAR1 ║ LOC99 ║ SUB99 ║ January, 05 2015 05:05:05+0000 ║
║ CAR1 ║ LOC1 ║ SUB1 ║ January, 09 2015 09:09:09+0000 ║
║ CAR2 ║ LOC1 ║ SUB2 ║ January, 03 2015 03:03:03+0000 ║
║ CAR2 ║ LOC1 ║ SUB1 ║ January, 04 2015 04:04:04+0000 ║
║ CAR2 ║ LOC99 ║ SUB99 ║ January, 05 2015 05:05:05+0000 ║
║ CAR2 ║ LOC1 ║ SUB1 ║ January, 09 2015 09:09:09+0000 ║
║ CAR3 ║ LOC2 ║ SUB1 ║ January, 15 2015 15:15:15+0000 ║
╚═════════╩════════════╩═══════════════╩════════════════════════════════╝
은 물론, 당신은 그냥 동시에 조건의 다양성을 테스트하기 위해 그렇게하고 있어요 dt_ranges에 대한 테이블을 사용할 필요가 없습니다. 나는 [currentstart, nextstart]의 관점에서 날짜 범위를 작업하는 편이 낫다. 예를 들어, 겹치지 않을 SQL을 작성하는 것이 훨씬 쉬워진다. 월별 보고서.
create table dt_range
(thisStartDate date,
nextStartDate date,
primary key (thisStartDate,nextStartDate));
insert into dt_range
select '01-dec-2014','01-jan-2015' union
select '01-jan-2015','01-feb-2015' union
select '02-jan-2015','09-jan-2015' union
select '01-feb-2015','01-mar-2015' ;
╔═══════════════╦═══════════════╗
║ THISSTARTDATE ║ NEXTSTARTDATE ║
╠═══════════════╬═══════════════╣
║ 2014-12-01 ║ 2015-01-01 ║
║ 2015-01-01 ║ 2015-02-01 ║
║ 2015-01-02 ║ 2015-01-09 ║
║ 2015-02-01 ║ 2015-03-01 ║
╚═══════════════╩═══════════════╝
그리고 쿼리 :
select thisStartDate, nextStartDate, t.AssetID, ArrivalLocation,
round(sum(datediff(ss,ArrivalTime, DepartureTime))/(24.0*60*60),1) DaysAtLoc
from (
select thisStartDate, nextStartDate, t.AssetID, ArrivalLocation, ArrivalTime,
coalesce(min(MoveDate),nextStartDate) DepartureTime
from (
select assetsInRange.thisStartDate, assetsInRange.nextStartDate, assetsInRange.assetID,
coalesce(ArrivalLocation,InitialLocation) ArrivalLocation,
coalesce(ArrivalTime,assetsInRange.thisStartDate) ArrivalTime
from
(
select thisStartDate, nextStartDate, assetID
from dt_range
join t1 on MoveDate < nextStartDate
group by thisStartDate, nextStartDate, assetID
) assetsInRange
left outer join
(
select thisStartDate, nextStartDate, assetID,
max(MoveDate) precedingDtRangeMoveDt
from dt_range
join t1
on MoveDate < thisStartDate
group by thisStartDate, nextStartDate, assetID
)
precedingMoveDt
on (assetsInRange.assetID = precedingMoveDt.assetID)
left outer join
(
select AssetID, MoveDate precedingDtRangeMoveDt, LocationID initialLocation
from t1
)
precedingMoveLoc
on (precedingMoveDt.assetID = precedingMoveLoc.AssetID
and precedingMoveDt.precedingDtRangeMoveDt = precedingMoveLoc.precedingDtRangeMoveDt)
left outer join
(
select AssetId, LocationId ArrivalLocation, MoveDate ArrivalTime
from t1
)
arrivals
on assetsInRange.AssetID = arrivals.AssetId
and ArrivalTime >= assetsInRange.thisStartDate
and ArrivalTime < assetsInRange.nextStartDate
group by assetsInRange.thisStartDate, assetsInRange.nextStartDate, assetsInRange.AssetId,
coalesce(ArrivalLocation,InitialLocation) ,
coalesce(ArrivalTime,assetsInRange.thisStartDate)
) t
left join t1 on t.assetID = t1.assetID
and t1.MoveDate > ArrivalTime
and t1.MoveDate < nextStartDate
group by thisStartDate, nextStartDate, t.AssetID, ArrivalLocation, ArrivalTime
) t
group by thisStartDate, nextStartDate, t.AssetID, ArrivalLocation
order by 1, 3;
그리고 결과 :
╔═══════════════╦═══════════════╦═════════╦═════════════════╦═══════════╗
║ THISSTARTDATE ║ NEXTSTARTDATE ║ ASSETID ║ ARRIVALLOCATION ║ DAYSATLOC ║
╠═══════════════╬═══════════════╬═════════╬═════════════════╬═══════════╣
║ 2015-01-01 ║ 2015-02-01 ║ CAR1 ║ LOC1 ║ 26.8 ║
║ 2015-01-01 ║ 2015-02-01 ║ CAR1 ║ LOC99 ║ 4.2 ║
║ 2015-01-01 ║ 2015-02-01 ║ CAR2 ║ LOC1 ║ 24.7 ║
║ 2015-01-01 ║ 2015-02-01 ║ CAR2 ║ LOC99 ║ 4.2 ║
║ 2015-01-01 ║ 2015-02-01 ║ CAR3 ║ LOC2 ║ 16.4 ║
║ 2015-01-02 ║ 2015-01-09 ║ CAR1 ║ LOC1 ║ 2.1 ║
║ 2015-01-02 ║ 2015-01-09 ║ CAR1 ║ LOC99 ║ 3.8 ║
║ 2015-01-02 ║ 2015-01-09 ║ CAR2 ║ LOC1 ║ 2.1 ║
║ 2015-01-02 ║ 2015-01-09 ║ CAR2 ║ LOC99 ║ 3.8 ║
║ 2015-02-01 ║ 2015-03-01 ║ CAR1 ║ LOC1 ║ 28 ║
║ 2015-02-01 ║ 2015-03-01 ║ CAR2 ║ LOC1 ║ 28 ║
║ 2015-02-01 ║ 2015-03-01 ║ CAR3 ║ LOC2 ║ 28 ║
╚═══════════════╩═══════════════╩═════════╩═════════════════╩═══════════╝
주 - 나는 자산에 대한 최초의 기록은 이전에 어떤 위치에 존재하지 않는 나타냅니다 가정 .. 따라서 2014 년 이전 날짜가있는 자산이 없으므로 2014 년 12 월 -18 월 테스트 월이 결과에 표시되지 않습니다.
LAG 창 기능을 사용하여이 작업을 수행 할 수 있지만 Azure 데이터베이스에서 지원되는지 여부는 알 수 없습니다. 그렇지 않으면 CTE를 사용해야하거나 하위 쿼리 –
명을 수행해야 할 수도 있습니다. 도움을 많이 주셔서 감사합니다. 불행히도 SQL Azure에는 LEAD 또는 LAG 기능이 없습니다. 간단한 조인은 트릭을합니다 !!! –
다음 질문은 1/6/2015-1/8/2015 기간에 대해 해당 자산이 각 위치에 머무는 기간을 물음표에 추가하는 방법을 파악하는 것입니다. 나는 그것을 파악하기 위해 저장된 proc 파일로 파열해야 할 수도 있습니다. –