2013-07-04 49 views
-2

我必須計算每個工作人員的班次時間。TSQL將行轉換爲列或將行分組

我寫了一個查詢,從我們的OLTP系統獲取數據並返回日期,員工及其登錄註銷時間。登錄和註銷時間是系統中的兩個單獨事務,但我希望在單行中登錄和註銷時間。看到下面的圖像,我得到的輸入和我想要的輸出。請幫助寫下一個查詢來實現我的目標。

Rows into columns

+3

_I已經寫了一個查詢來獲取data_也許你應該考慮發佈你試過的查詢。 – Taryn

回答

1

你真正想要的是什麼lag()功能,但不可用在SQL Server 2008中所以,你可以使用子查詢效仿:

 select i.day, i.staff, i.login, 
      (select top 1 logout 
       from input i2 
       where i2.staff = i.staff and 
        i2.day = i.day and 
        i2.login = cast(login as date) and 
        i2.logout >= i.login 
       order by i2.logout 
      ) as LogOut 
     from input i 
     where logout = cast(logout as date) 

邏輯logout = cast(logout as date)意以確定logout對於時間分量具有零的行。

這裏假定沒有任何轉變會在午夜之後結束。

編輯:

在SQL Server 2012中,您可以使用相同的查詢。與lead()替換它是一些工作:需要

 select day, staff, login, logout 
     from (select i.day, i.staff, thedate as login, which, 
        lead(thedate) over (partition by staff, day order by date) as LogOut 
      from (select i.day, i.staff, 
         (case when login = cast(login as date) then logout 
           else login 
          end) as thedate, 
         (case when login = cast(login as date) then 'logout' 
           else 'login' 
          end) as which 
        from input i 
       ) i 
      ) i 
     where which = 'login' 

更多的子查詢。問題在於你要比較兩個字段中的日期,所以最內層的子查詢將它們放在一個字段中('thedate')。接下來找到下一個日期(當一行是登錄時它假定是註銷,最外面只是選擇登錄行)。

說實話,我認爲我更喜歡第一個版本的子查詢,因爲你的數據結構

+0

Gordon,我使用SQL Server2012。請修改查詢,並讓我知道如何使用滯後函數。謝謝 –

+4

@RizwanMalik那麼爲什麼要使用[tag:sql-server-2008]標籤? – Lamak

+0

我現在已經標記了Sql server 2012.請問您可以修改查詢,因爲上面的查詢沒有給出任何結果 –

0

當我必須對數據進行非規範化時,我喜歡使用自連接。我在SQL Server 2012上測試了以下內容。(但是,一般方法應該支持任何支持自連接的SQL RDBS,但是你必須修改的情況下,逐案的DATETIME2數據類型和函數調用)

數據:

DECLARE @t1 AS TABLE (
    Day1 DATE 
    ,Staff VARCHAR(3) 
    ,Login DATETIME2 
    ,Logout DATETIME2 
); 

INSERT INTO @t1 
VALUES ('20130704', '123', '20130704 18:44:16.533', '20130704 00:00:00.000') 
,('20130706', '456', '20130706 00:00:00.000', '20130706 01:10:12.000') 
,('20130704', '123', '20130704 00:00:00.000', '20130704 20:24:16.553') 
,('20130704', '123', '20130704 20:44:16.533', '20130704 00:00:00.000') 
,('20130704', '123', '20130704 00:00:00.000', '20130704 22:54:16.553') 
,('20130705', '456', '20130705 08:45:12.550', '20130705 00:00:00.000'); 

解決方案:

SELECT a.Day1, a.Staff, a.Login, MIN(b.Logout) AS Logout, 
    DateDiff(minute, a.login, MIN(b.logout)) AS Elapsed 
FROM @t1 a join @t1 b 
    ON a.Staff = b.Staff AND a.Login < b.Logout AND CONVERT(TIME, a.Login) > '00:00:00.00' 
GROUP BY a.Day1, a.Staff, a.Login; 

其他注意事項:

  1. 你剛纔提到你要計算的時間。這可以在相同的查詢中完成。在這種情況下,'Elapsed'列計算分鐘數。 (變化DateDiff的第一個參數hour你的目的。)

@Gordon Linoff

  1. 查詢正確處理的情況下,如果登錄爲一天和註銷是不同的一天。