2013-07-04 52 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. 查询正确处理的情况下,如果登录为一天和注销是不同的一天。