SQL最后一次超时(Transact-SQL..preferrably)

时间:2013-07-01 06:08:12

标签: sql sql-server tsql

我有下表,其中包含人员的所有时间和时间:

 CREATE TABLE test (
       timecardid INT
     , trandate DATE
     , employeeid INT
     , trantime TIME
     , Trantype VARCHAR(1)
     , Projcode VARCHAR(3)
)

任务是获得所有最早的trantime与trantype A(可能使用MIN)和最新trantime与trantype Z(使用Max),所有这些trandate(即7月17日的trantype A是8:00) AM和trantype Z为7月17日是晚上7点。

问题是,输出应该与它来自的表格格式相同,这意味着我必须保留这些数据并过滤掉其余的数据(这不是最早的和最新的输入/输出)日期,每位员工)

我目前的解决方案是使用两个不同的选择命令来获得所有最早的,然后获取所有最新的。然后将它们结合起来。

我想知道,是否有更简单的单字符串解决方案?

非常感谢。

编辑(我道歉,这是示例。服务器是SQL Server 2008):

 Timecardid | Trandate | employeeid | trantime | trantype | Projcode 
      1      2013-04-01      1        8:00:00        A       SAMPLE1
      2      2013-04-01      1        9:00:00        A       SAMPLE1
      3      2013-04-01      2        7:00:00        A       SAMPLE1
      4      2013-04-01      2        6:59:59        A       SAMPLE1
      5      2013-04-01      1       17:00:00        Z       SAMPLE1
      6      2013-04-01      1       17:19:00        Z       SAMPLE1
      7      2013-04-01      2        17:00:00       Z       SAMPLE1

      8      2013-04-02      1        8:00:00        A       SAMPLE1
      9      2013-04-02      1        9:00:00        A       SAMPLE1
     10      2013-04-02      2        7:00:58        A       SAMPLE1
     11      2013-04-02      2       18:00:00        Z       SAMPLE1
     12      2013-04-02      2       18:00:01        Z       SAMPLE1
     13      2013-04-02      1       20:00:00        Z       SAMPLE1

预期结果(每个员工中最早的和最新的,每个员工,在一个选择命令中):

  Timecardid | Trandate | employeeid | trantime | trantype | Projcode 
      1      2013-04-01      1        8:00:00        A       SAMPLE1 
      4      2013-04-01      2        6:59:59        A       SAMPLE1   
      6      2013-04-01      1       17:19:00        Z       SAMPLE1
      7      2013-04-01      2        17:00:00       Z       SAMPLE1
      8      2013-04-02      1        8:00:00        A       SAMPLE1
     10      2013-04-02      2        7:00:58        A       SAMPLE1
     12      2013-04-02      2       18:00:01        Z       SAMPLE1
     13      2013-04-02      1       20:00:00        Z       SAMPLE1

非常感谢

4 个答案:

答案 0 :(得分:2)

也许这就是你要找的东西:

select 
    t.* 
from 
    test t
where 
    trantime in (
        (select min(trantime) from test t1 where t1.trandate = t.trandate and trantype = 'A'),
        (select max(trantime) from test t2 where t2.trandate = t.trandate and trantype = 'Z')
    )

将我的答案更改为“每位员工”要求的帐户:

;WITH EarliestIn AS
(
    SELECT trandate, employeeid, min(trantime) AS EarliestTimeIn
    FROM test 
    WHERE trantype = 'A'
    GROUP BY trandate, employeeid 
), 
LatestOut AS
(
    SELECT trandate, employeeid, max(trantime) AS LatestTimeOut
    FROM test 
    WHERE trantype = 'Z'
    GROUP BY trandate, employeeid 
)
SELECT * 
FROM test t
WHERE 
    EXISTS (SELECT * FROM EarliestIn WHERE t.trandate = EarliestIn.trandate AND t.employeeid = EarliestIn.employeeid AND t.trantime = EarliestIn.EarliestTimeIn) 
    OR EXISTS (SELECT * FROM LatestOut WHERE t.trandate = LatestOut.trandate AND t.employeeid = LatestOut.employeeid AND t.trantime = LatestOut.LatestTimeOut)

答案 1 :(得分:1)

假设timecardid列是PK或唯一的,如果我理解正确,我会做类似的事情

DECLARE @date DATE
SET @date = '2013-07-01'

SELECT
    T0.*
FROM
    (SELECT DISTINCT employeeid FROM test) E
    CROSS APPLY (
        SELECT TOP 1
            T.timecardid
        FROM
            test T
        WHERE
            T.trandate = @date
            AND T.Trantype = 'A'
            AND T.employeeid = E.employeeid
        ORDER BY T.trantime
        UNION ALL
        SELECT TOP 1
            T.timecardid
        FROM
            test T
        WHERE
            T.trandate = @date
            AND T.Trantype = 'Z'
            AND T.employeeid = E.employeeid
        ORDER BY T.trantime DESC
    ) V
    JOIN test T0 ON T0.timecardid = V.timecardid

如果您了解性能,则应为表格设置适当的索引。

答案 2 :(得分:1)

我会使用ROW_NUMBER来整理您要选择的行:

;with Ordered as (
  select *,
    ROW_NUMBER() OVER (PARTITION BY Trandate,employeeid,trantype
        ORDER BY trantime ASC) as rnEarly,
    ROW_NUMBER() OVER (PARTITION BY Trandate,employeeid,trantype
        ORDER BY trantime DESC) as rnLate
  from
    Test
)
select * from Ordered
where
  (rnEarly = 1 and trantype='A') or
  (rnLate = 1 and trantype='Z')
order by TimecardId

SQLFiddle

它会产生您所要求的结果,我认为它非常易读。 trantype条款中包含PARTITION BY的原因是AZ值会收到单独的编号。

答案 3 :(得分:1)

如果您使用的是SQL Server 2012,则可以使用LAG / LEAD以相当简洁的方式查找最大行数和最小行数;

WITH cte AS (
  SELECT *,
       LAG(timecardid)  OVER (PARTITION BY trandate,employeeid,trantype ORDER BY trantime)  lagid,
       LEAD(timecardid) OVER (PARTITION BY trandate,employeeid,trantype ORDER BY trantime) leadid
  FROM test
)
SELECT timecardid,trandate,employeeid,trantime,trantype,projcode
FROM cte
WHERE trantype='A' AND lagid  IS NULL
   OR trantype='Z' AND leadid IS NULL;

An SQLfiddle to test with