2016-12-26 47 views
1

我只需要按ID在一個分區中的前100個密鑰和即將到來的101個密鑰之間的日期時間差異,即如果下一個密鑰值也爲101,則採用該關鍵日期時間值,即id = 1。 101鍵即將到來的100鍵也一樣。我嘗試使用窗口函數,但沒有得到確切的答案。比較SQL Server中的第一行和第n行

ID Name Key  datetime 
1 AAA  100  2016-07-01 09:32:48.000 
1 AAA  100  2016-07-01 13:31:02.000 
1 AAA  100  2016-07-01 14:10:57.000 
1 AAA  101  2016-07-01 15:12:09.000 
1 AAA  100  2016-07-01 15:12:17.000 
1 AAA  100  2016-07-01 15:18:36.000 
1 AAA  101  2016-07-01 15:34:16.000 
2 BBB  100  2016-07-04 09:26:15.000 
2 BBB  100  2016-07-04 13:40:52.000 
2 BBB  101  2016-07-04 14:18:26.000 
2 BBB  101  2016-07-04 18:34:29.000 
2 BBB  100  2016-07-04 18:34:32.000 
2 BBB  101  2016-07-04 23:04:32.000 

進出料應該像

ID Name Key  datetime     In   Out 
1 AAA  100  2016-07-01 09:32:48.000 05:39:21  
1 AAA  100  2016-07-01 13:31:02.000  
1 AAA  100  2016-07-01 14:10:57.000  
1 AAA  101  2016-07-01 15:12:09.000    00:06:27 
1 AAA  100  2016-07-01 15:12:17.000 00:21:59  
1 AAA  100  2016-07-01 15:18:36.000  
1 AAA  101  2016-07-01 15:34:16.000  
2 BBB  100  2016-07-04 09:26:15.000 09:08:14  
2 BBB  100  2016-07-04 13:40:52.000  
2 BBB  101  2016-07-04 14:18:26.000  
2 BBB  101  2016-07-04 18:34:29.000    00:00:03 
2 BBB  100  2016-07-04 18:34:32.000 04:30:00  
2 BBB  101  2016-07-04 23:04:32.000  
+2

添加預期的輸出 –

+0

古溫德·辛格datetime列值之差即差 '2016年7月1日09:32:48.000' 和「2016年7月1日15 :12:09.000' – Jalandhar

+1

請編輯您的問題並解釋輸出 – TheGameiswar

回答

0

下面是做這件事(假設SQL Server 2012中或更高版本)

首先,創建和填充示例表(,請將您的未來問題省略我們這一步)

DECLARE @T AS TABLE 
(
    Id int, 
    Name char(3), 
    [Key] int, 
    [datetime] DateTime 
) 

INSERT INTO @T VALUES 
(1, 'AAA', 100, '2016-07-01 09:32:48.000'), 
(1, 'AAA', 100, '2016-07-01 13:31:02.000'), 
(1, 'AAA', 100, '2016-07-01 14:10:57.000'), 
(1, 'AAA', 101, '2016-07-01 15:12:09.000'), 
(1, 'AAA', 100, '2016-07-01 15:12:17.000'), 
(1, 'AAA', 100, '2016-07-01 15:18:36.000'), 
(1, 'AAA', 101, '2016-07-01 15:34:16.000'), 
(2, 'BBB', 100, '2016-07-04 09:26:15.000'), 
(2, 'BBB', 100, '2016-07-04 13:40:52.000'), 
(2, 'BBB', 101, '2016-07-04 14:18:26.000'), 
(2, 'BBB', 101, '2016-07-04 18:34:29.000'), 
(2, 'BBB', 100, '2016-07-04 18:34:32.000'), 
(2, 'BBB', 101, '2016-07-04 23:04:32.000') 

查詢:

SELECT Id, 
     Name, 
     [Key], 
     [DateTime], 
     CASE WHEN [Key] = 100 AND ISNULL(LAG([Key]) OVER(PARTITION BY Id ORDER BY [DateTime]), 101) <> 100 THEN 
      CAST(
       (SELECT TOP 1 [DateTime] 
       FROM @T subQuery 
       WHERE subQuery.[Key] = 101 
       AND subQuery.Id = outerQuery.Id 
       AND subQuery.[DateTime] > outerQuery.[DateTime] 
       ORDER BY [DateTime] 
       ) - [DateTime] 
      As Time) 
     ELSE 
      NULL 
     END As [In], 
     CASE WHEN [Key] = 101 AND ISNULL(LAG([Key]) OVER(PARTITION BY Id ORDER BY [DateTime]), 100) <> 101 THEN 
      CAST(
       (SELECT TOP 1 [DateTime] 
       FROM @T subQuery 
       WHERE subQuery.[Key] = 100 
       AND subQuery.Id = outerQuery.Id 
       AND subQuery.[DateTime] > outerQuery.[DateTime] 
       ORDER BY [DateTime] 
       ) - [DateTime] 
      As Time) 
     ELSE 
      NULL 
     END As [Out] 
FROM @T outerQuery 

結果:

Id Name Key  DateTime    In   Out 
1 AAA  100  01.07.2016 09:32:48  05:39:21  
1 AAA  100  01.07.2016 13:31:02    
1 AAA  100  01.07.2016 14:10:57    
1 AAA  101  01.07.2016 15:12:09     00:00:08 
1 AAA  100  01.07.2016 15:12:17  00:21:59  
1 AAA  100  01.07.2016 15:18:36    
1 AAA  101  01.07.2016 15:34:16    
2 BBB  100  04.07.2016 09:26:15  04:52:11  
2 BBB  100  04.07.2016 13:40:52    
2 BBB  101  04.07.2016 14:18:26     04:16:06 
2 BBB  101  04.07.2016 18:34:29    
2 BBB  100  04.07.2016 18:34:32  04:30:00  
2 BBB  101  04.07.2016 23:04:32    
+0

你快到了。我正在研究類似的答案。從這個問題:'如果下一個鍵值也是101,那麼取這個關鍵日期時間值'這意味着你的結果第10行與out ='04:16:06'是不同於他的預期輸出。 – SqlZim

+0

嗯,我想我有點誤解了那部分...不要以爲我會有時間來修改我今天的答案,也許明天。 –

+0

謝謝你Zohar Peled你解決了我的問題。有性能問題,但得到了解決方案,謝謝。 – Jalandhar

0

萬一沒人走來幫忙,你可以試試這個。這是一團糟,但與測試數據一起工作。

rextester:http://rextester.com/MPD86507

create table KeySwipeLog (Id int, Name char(3),KeyCard int, dt datetime); 
insert into KeySwipeLog values 
    (1,'aaa',100,'2016-07-01 09:32:48.000') 
    ,(1,'aaa',100,'2016-07-01 13:31:02.000') 
    ,(1,'aaa',100,'2016-07-01 14:10:57.000') 
    ,(1,'aaa',101,'2016-07-01 15:12:09.000') 
    ,(1,'aaa',100,'2016-07-01 15:12:17.000') 
    ,(1,'aaa',100,'2016-07-01 15:18:36.000') 
    ,(1,'aaa',101,'2016-07-01 15:34:16.000') 
    ,(2,'bbb',100,'2016-07-04 09:26:15.000') 
    ,(2,'bbb',100,'2016-07-04 13:40:52.000') 
    ,(2,'bbb',101,'2016-07-04 14:18:26.000') 
    ,(2,'bbb',101,'2016-07-04 18:34:29.000') 
    ,(2,'bbb',100,'2016-07-04 18:34:32.000') 
    ,(2,'bbb',101,'2016-07-04 23:04:32.000'); 


with cte as (
    select 
     Id 
    , Name 
    , Keycard 
    , Dt 
    , ignore = case 
     when KeyCard = 100 
      and isnull(lag(k.KeyCard) over (partition by k.Id order by k.dt),0)!=100 
      then 0 
     when KeyCard = 101 and isnull(lead(k.KeyCard) over (partition by k.Id order by k.dt),0)!=101 
      then 0 
     else 1 
     end 
     /* When the next Keycard is also 101, skip the current record for calculating in times*/ 
     , in_ignore = case 
     when KeyCard = 101 
      and isnull(lead(k.KeyCard) over (partition by k.Id order by k.dt),0)!=101 
      then 0 
     --when KeyCard = 100 then null 
     else 1 
     end 
     /* When the next Keycard is also 100, skip the current record for calculating out times*/ 
     , out_ignore = case 
     when KeyCard = 100 
      and isnull(lead(k.KeyCard) over (partition by k.Id order by k.dt),0) = 100 
      then 1 
     --when KeyCard = 101 then 1 
     else 0 
     end 
    from KeySwipeLog as k 
    ) 

select 
    k.Id 
    , k.Name 
    , k.KeyCard 
    , k.dt 
    --, k.ignore 
    --, k.in_ignore 
    --, k.out_ignore 
, [in] =case 
    when k.KeyCard=100 
    and i.dt is not null 
    and k.ignore = 0 
    then convert(varchar(8),convert(time(0),i.dt-k.dt)) 
    else '' 
    end 
, out=case 
    when k.KeyCard=101 
    and o.dt is not null 
    and k.ignore = 0 
    then convert(varchar(8),convert(time(0),o.dt-k.dt)) 
    else '' 
    end 
--, i.* 
--, o.* 
    from cte as k 
     outer apply (
      select top 1 * 
      from cte as x 
      where x.Id=k.Id 
      and x.dt>k.dt 
      and x.keycard!=k.keycard 
      and x.in_ignore=0 
      order by dt asc 
     ) as i 
     outer apply (
      select top 1 * 
      from cte as x 
      where x.Id=k.Id 
      and x.dt>k.dt 
      and x.keycard!=k.keycard 
      and x.out_ignore=0 
      order by dt asc 
     ) as o 

    order by k.Id, k.dt 
0
 DECLARE @T AS TABLE 
     (
     Id int, 
     Name char(3), 
     [Key] int, 
     [datetime] DateTime 
     ) 

     INSERT INTO @T VALUES 
     (1, 'AAA', 100, '2016-07-01 09:32:48.000'), 
     (1, 'AAA', 100, '2016-07-01 13:31:02.000'), 
     (1, 'AAA', 100, '2016-07-01 14:10:57.000'), 
     (1, 'AAA', 101, '2016-07-01 15:12:09.000'), 
     (1, 'AAA', 100, '2016-07-01 15:12:17.000'), 
     (1, 'AAA', 100, '2016-07-01 15:18:36.000'), 
     (1, 'AAA', 101, '2016-07-01 15:34:16.000'), 
     (2, 'BBB', 100, '2016-07-04 09:26:15.000'), 
     (2, 'BBB', 100, '2016-07-04 13:40:52.000'), 
     (2, 'BBB', 101, '2016-07-04 14:18:26.000'), 
     (2, 'BBB', 101, '2016-07-04 18:34:29.000'), 
     (2, 'BBB', 100, '2016-07-04 18:34:32.000'), 
     (2, 'BBB', 101, '2016-07-04 23:04:32.000') 


     ;with cte as 
     (

     SELECT *,ROW_NUMBER() OVER(PARTITION BY ID,NAMe ORDER BY [datetime])RN, 
      CASE WHEN LAG([Key],1) OVER(PARTITION BY ID,NAMe ORDER BY [datetime]) = [KEY] THEN 0 ELSE 1 END IsDiffer 
     FROM @t 
     ) 

     SELECT c1.*, 
       CASE WHEN c1.[Key] = 100 THEN 
        CAST(DATEDIFF(ss,c1.[datetime],E.[datetime]) /3600 AS VARCHAR) +':'+ 
       CAST((DATEDIFF(ss,c1.[datetime],E.[datetime]) %3600)/60 AS VARCHAR) +':'+ 
       CAST((DATEDIFF(ss,c1.[datetime],E.[datetime]) %60) AS VARCHAR) END [IN], 
       CASE WHEN c1.[Key] = 101 THEN 
        CAST(DATEDIFF(ss,c1.[datetime],E.[datetime]) /3600 AS VARCHAR) +':'+ 
       CAST((DATEDIFF(ss,c1.[datetime],E.[datetime]) %3600)/60 AS VARCHAR) +':'+ 
       CAST((DATEDIFF(ss,c1.[datetime],E.[datetime]) %60) AS VARCHAR) END [OUT] 

     FROM CTE c1 
     OUTER APPLY 
     (
     SELECT TOP 1 * FROM cte c2 
     where c1.id = c2.id and c1.name = c2.name 
     and c2.IsDiffer = 1 and c1.IsDiffer = 1 
     and c1.rn <c2.rn 
     ORDER BY RN 
     )E 
相關問題