2012-02-21 60 views
2

我需要以下情況的幫助。計算用戶唯一的開始結束時間集合

此表在SQL Server 2005上。如果您覺得2008年的某些功能會有幫助,我們也可以訪問SQL Server 2008。儘管如此,我可以做到這一點。 :)

我有一個系統100多個用戶的登錄時間。他們可以同時登錄到不同的頻道。

我需要有端到端登錄註銷時候,不論通道

我猜,這可以通過一個存儲過程來完成。但如果它沒有達到性能,我可以接受任何其他選擇。

以下AgentResults2是我的基礎表。

AgentOutcome表是我想要的樣子。

基表

FUser_id   FLoginDt     FLogoutDt 
30001    2012-02-17 12:32:15.473 2012-02-17 14:15:36.547 
30001    2012-02-17 12:49:48.177 2012-02-17 14:10:01.097 
30001    2012-02-17 14:30:49.293 2012-02-17 15:41:02.387 

該用戶登錄到一個信道以12.32呆在那裏直到14:15此期間,他也登錄到另一個channelat 12點49分,在那裏呆直到14內的一個例子: 10。並於14:30至15:41進行了新的登錄。我想從這裏得到兩行是

FUser_id   FLoginDt     FLogoutDt 
30001    2012-02-17 12:32:15.473 2012-02-17 14:15:36.547 
30001    2012-02-17 14:30:49.293 2012-02-17 15:41:02.387 

,當你在用戶39395

SET DATEFORMAT DMY 

IF OBJECT_ID('#AgentResults2', 'U') IS NOT NULL DROP TABLE #AgentResults2; 

CREATE TABLE #AgentResults2 (FUser_id varchar(48), FLoginDt datetime, FLogoutDt DateTime) 

Insert Into #AgentResults2 (FUser_id , FLoginDt, FLogoutDt) 
Select '30001','17/02/2012 8:09:23.117 AM' ,'17/02/2012 8:39:28.527 AM' UNION ALL 
Select '30001','17/02/2012 8:50:26.087 AM','17/02/2012 9:31:32.040 AM' UNION ALL 
Select '30001','17/02/2012 10:28:42.430 AM','17/02/2012 10:54:13.880 AM' UNION ALL 
Select '30001','17/02/2012 10:59:20.567 AM','17/02/2012 12:00:36.030 PM' UNION ALL 
Select '30001','17/02/2012 12:32:15.473 PM','17/02/2012 2:15:36.547 PM' UNION ALL 
Select '30001','17/02/2012 12:49:48.177 PM','17/02/2012 2:10:01.097 PM' UNION ALL 
Select '30001','17/02/2012 2:30:49.293 PM','17/02/2012 3:41:02.387 PM' UNION ALL 
Select '30001','17/02/2012 3:44:05.800 PM','17/02/2012 4:01:33.613 PM' UNION ALL 
Select '39300','17/02/2012 8:06:31.250 AM','17/02/2012 3:51:31.930 PM' UNION ALL 
Select '39300','17/02/2012 10:15:08.923 AM','17/02/2012 10:21:29.833 AM' UNION ALL 
Select '39363','17/02/2012 9:58:44.287 AM','17/02/2012 11:20:08.950 AM' UNION ALL 
Select '39363','17/02/2012 11:20:29.203 AM','17/02/2012 1:27:36.717 PM' UNION ALL 
Select '39363','17/02/2012 1:27:36.717 PM','17/02/2012 3:05:12.383 PM' UNION ALL 
Select '39363','17/02/2012 3:05:31.527 PM','17/02/2012 4:57:13.733 PM' UNION ALL 
Select '39363','17/02/2012 4:57:44.640 PM','17/02/2012 5:59:20.273 PM' UNION ALL 
Select '39395','17/02/2012 9:37:14.353 AM','17/02/2012 10:15:52.397 AM' UNION ALL 
Select '39395','17/02/2012 10:15:28.427 AM','17/02/2012 10:58:47.080 AM' UNION ALL 
Select '39395','17/02/2012 10:57:03.590 AM','17/02/2012 11:53:47.933 AM' UNION ALL 
Select '39395','17/02/2012 11:51:31.567 AM','17/02/2012 2:26:27.640 PM' UNION ALL 
Select '39395','17/02/2012 2:31:30.247 PM','17/02/2012 4:04:44.217 PM' UNION ALL 
Select '39395','17/02/2012 4:10:49.013 PM','17/02/2012 4:11:26.983 PM' UNION ALL 
Select '39395','17/02/2012 4:17:16.813 PM','17/02/2012 5:55:47.187 PM' UNION ALL 
Select '39395','17/02/2012 4:55:25.900 PM','17/02/2012 5:26:07.310 PM' ; 

Select * from #AgentResults2; 

IF OBJECT_ID('#AgentOutcome', 'U') IS NOT NULL DROP TABLE #AgentOutcome; 

CREATE TABLE #AgentOutcome (FUser_id varchar(48), FLoginDt datetime, FLogoutDt DateTime) 

Insert Into #AgentOutcome (FUser_id , FLoginDt, FLogoutDt) 

Select '30001','17/02/2012 8:09:23.117 AM','17/02/2012 8:39:28.527 AM' UNION ALL 
Select '30001','17/02/2012 8:50:26.087 AM','17/02/2012 9:31:32.040 AM' UNION ALL 
Select '30001','17/02/2012 10:28:42.430 AM','17/02/2012 10:54:13.880 AM' UNION ALL 
Select '30001','17/02/2012 10:59:20.567 AM','17/02/2012 12:00:36.030 PM' UNION ALL 
Select '30001','17/02/2012 12:32:15.473 PM','17/02/2012 2:15:36.547 PM' UNION ALL 
Select '30001','17/02/2012 2:30:49.293 PM','17/02/2012 3:41:02.387 PM' UNION ALL 
Select '30001','17/02/2012 3:44:05.800 PM','17/02/2012 4:01:33.613 PM' UNION ALL 
Select '39300','17/02/2012 8:06:31.250 AM','17/02/2012 3:51:31.930 PM' UNION ALL 
Select '39363','17/02/2012 9:58:44.287 AM','17/02/2012 11:20:08.950 AM' UNION ALL 
Select '39363','17/02/2012 11:20:29.203 AM','17/02/2012 3:05:12.383 PM' UNION ALL 
Select '39363','17/02/2012 3:05:31.527 PM','17/02/2012 4:57:13.733 PM' UNION ALL 
Select '39363','17/02/2012 4:57:44.640 PM','17/02/2012 5:59:20.273 PM' UNION ALL 
Select '39395','17/02/2012 9:37:14.353 AM','17/02/2012 2:26:27.640 PM' UNION ALL 
Select '39395','17/02/2012 2:31:30.247 PM','17/02/2012 4:04:44.217 PM' UNION ALL 
Select '39395','17/02/2012 4:10:49.013 PM','17/02/2012 4:11:26.983 PM' UNION ALL 
Select '39395','17/02/2012 4:17:16.813 PM','17/02/2012 5:55:47.187 PM' ; 

Select * from #AgentOutcome; 

DROP TABLE #AgentResults2; 
DROP TABLE #AgentOutcome; 

我已經檢查了其他相關的主題,他們接近,但更具體的聚合就變得複雜並滿足min開始& mx結束時間。

我正在使用的代碼是

;with Ranges as ( 
    select FUser_id,FloginDt,FlogoutDt 
    from #AgentResults2 
    union all 
     select r.FUser_id,r.FloginDt,t.FLogoutdt 
    from 
     Ranges r 
      inner join 
     #AgentResults2 t 
      on 
       r.FUser_id = t.FUser_Id and DATEDIFF(ms,r.Flogoutdt,t.FloginDt) = 0 
), 
ExtendedRanges as ( 
select FUser_id,MIN(FloginDt) as FloginDt,Flogoutdt 
from Ranges 
group by FUser_ID,Flogoutdt 
) 
select FUser_Id,FloginDt,MAX(Flogoutdt) 
from ExtendedRanges 
group by FUser_id,FloginDt 
order by 1 
    OPTION (MAXRECURSION 0) 
+0

也許搜索SQL重疊範圍,例如[這個問題](http://stackoverflow.com/questions/4345910/merge-rows-based-on-date-in-sql-server) – 2012-02-21 08:14:34

+0

謝謝@Damien_The_Unbeliever指向我的另一個問題。看完這個問題後,我很高興 - 認爲就是這樣。但是在做出相應的代碼之後,我沒有看到預期的結果。另一個問題有一個訣竅,就是將第二天結合在同一行中,但是,如果同一毫秒包含在同一行中,則我的結果是兩倍1)。 2)如果不到endtime還包括做一行。這並不完全符合我的情況。我附上了我在下一條評論中使用的代碼。 – CeeVei 2012-02-21 13:05:16

+0

如果您發佈複雜的代碼,最好編輯您的問題,以便您可以正確格式化它。 – 2012-02-21 13:12:55

回答

1

我覺得這已經得到了它:

;With Ranges as (
    select 
     a1.FUser_Id,a1.FLoginDt,a1.FLogoutDt 
    from 
     #AgentResults2 a1 
      left join 
     #AgentResults2 a_nooverlap_early 
      on 
       a1.FUser_id = a_nooverlap_early.FUser_id and 
       a_nooverlap_early.FLoginDt < a1.FLoginDt and 
       a_nooverlap_early.FLogoutDt >= a1.FLoginDt 
    where 
     a_nooverlap_early.FUser_id is null 
    union all 
    select r.FUser_Id,r.FLoginDt,a1.FLogoutDt 
    from 
     Ranges r 
      inner join 
     #AgentResults2 a1 
      on 
       r.FUser_id = a1.FUser_Id and 
       r.FLogoutDt >= a1.FLoginDt and 
       a1.FLogoutDt > r.FLogoutDt 
) 
select FUser_id,FLoginDt,MAX(FLogoutDt) as FLogoutDt from Ranges group by FUser_id,FLoginDt 

Ranges CTE的第一部分,發現有一個FLoginDt是ISN所有時間段」 t與另一個範圍重疊。 CTE的遞歸部分然後試圖找出與這些時期的FLogoutDt重疊的任何其他時間段,並且採用後來的FLogoutDt。然後最後的選擇將最新發現的FLogoutDt用於任何特定的FUser_id,FLoginDt組合 - 這應該是整個存在重疊的時期。

我還重新寫你的樣本數據,以便SET DATEFORMAT DMY沒有要求 - 日期格式我已經展示了始終都會安全/被明確地由SQL Server轉換爲datetime

CREATE TABLE #AgentResults2 (FUser_id varchar(48), FLoginDt datetime, FLogoutDt DateTime) 

Insert Into #AgentResults2 (FUser_id , FLoginDt, FLogoutDt) 
select '30001','2012-02-17T08:09:23.117','2012-02-17T08:39:28.527' union all 
select '30001','2012-02-17T08:50:26.087','2012-02-17T09:31:32.040' union all 
select '30001','2012-02-17T10:28:42.430','2012-02-17T10:54:13.880' union all 
select '30001','2012-02-17T10:59:20.567','2012-02-17T12:00:36.030' union all 
select '30001','2012-02-17T12:32:15.473','2012-02-17T14:15:36.547' union all 
select '30001','2012-02-17T12:49:48.177','2012-02-17T14:10:01.097' union all 
select '30001','2012-02-17T14:30:49.293','2012-02-17T15:41:02.387' union all 
select '30001','2012-02-17T15:44:05.800','2012-02-17T16:01:33.613' union all 
select '39300','2012-02-17T08:06:31.250','2012-02-17T15:51:31.930' union all 
select '39300','2012-02-17T10:15:08.923','2012-02-17T10:21:29.833' union all 
select '39363','2012-02-17T09:58:44.287','2012-02-17T11:20:08.950' union all 
select '39363','2012-02-17T11:20:29.203','2012-02-17T13:27:36.717' union all 
select '39363','2012-02-17T13:27:36.717','2012-02-17T15:05:12.383' union all 
select '39363','2012-02-17T15:05:31.527','2012-02-17T16:57:13.733' union all 
select '39363','2012-02-17T16:57:44.640','2012-02-17T17:59:20.273' union all 
select '39395','2012-02-17T09:37:14.353','2012-02-17T10:15:52.397' union all 
select '39395','2012-02-17T10:15:28.427','2012-02-17T10:58:47.080' union all 
select '39395','2012-02-17T10:57:03.590','2012-02-17T11:53:47.933' union all 
select '39395','2012-02-17T11:51:31.567','2012-02-17T14:26:27.640' union all 
select '39395','2012-02-17T14:31:30.247','2012-02-17T16:04:44.217' union all 
select '39395','2012-02-17T16:10:49.013','2012-02-17T16:11:26.983' union all 
select '39395','2012-02-17T16:17:16.813','2012-02-17T17:55:47.187' union all 
select '39395','2012-02-17T16:55:25.900','2012-02-17T17:26:07.310'; 
+0

從ExtendedRanges選擇FUser_Id,FloginDt,MAX(Flogoutdt) 組有沒有分析你的腳本尚未徹底,只是測試,它似乎並沒有涵蓋所有情況爲止。 '39300'行應該合併成一個(我認爲),但它們在腳本的輸出中保持單獨的行。我還添加了這一行:'select'30001','2012-02-17T08:39:28.527','2012-02-17T08:39:33.117'union all',我預料這應該會延長'30001 「的第一個範圍,並沒有(腳本似乎忽略了它)。 – 2012-02-22 12:54:11

+0

@AndriyM - 我有一個比較(應該有'> ='而不是'>')稍微錯了,我想,但我無法重現你39300問題 - 我只在輸出中得到一行。 – 2012-02-22 13:08:38

+0

現在沒什麼不對,兩個問題都沒有了。我必須說,這非常好!我的版本使用了ROW_NUMBER(),最終得到的查詢結果更加嚴重。 – 2012-02-22 13:30:03

相關問題