如何在MSSQL上执行此查询

时间:2014-04-08 16:31:56

标签: sql sql-server

我需要进行查询以显示每天的入口(Where TerminalID = 1)和退出(Where TerminalID = 2),但如果UserID只有这一天的退出标记,请使用08:00:00 on入口价值,如果没有退出标记,请在当天20:00:00设置退出值,我需要知道IDUser在这里的天数以及每天有多少时间,这是我的餐桌:

SQLFiddle

ID  TransactionTime TerminalID UserID
1   2014-04-01 08:59    1      1
2   2014-04-01 09:09    1      1
3   2014-04-01 09:59    2      1
4   2014-04-01 10:59    1      1
5   2014-04-01 18:59    2      1
6   2014-05-01 08:59    1      1
7   2014-04-01 09:59    1      2
8   2014-04-01 18:59    2      2
9   2014-05-01 08:59    2      2

我需要的结果是:

UserID  MarkEntrance    MarkExit          TimeHere
1     2014-04-01 08:59  2014-04-01 09:59  01:00:00
1     2014-04-01 10:59  2014-04-01 18:59  08:00:00
1     2014-05-01 08:59  2014-05-01 20:00  11:01:00

我可以这样做:

SELECT TOP 1000
      pna.UserID
      ,Convert(char(10),pna.TransactionTime, 103) as DateOfMark
      ,MarkEntrance = 
CASE WHEN 
(SELECT MIN(TransactionTime) FROM [NGAC_AUTHLOG] as na WHERE na.TerminalID = 1 AND Convert(char(10),na.TransactionTime, 103) = Convert(char(10),pna.TransactionTime, 103) AND na.UserID = pna.UserID ) IS NOT NULL
THEN 
(SELECT MIN(TransactionTime) FROM [NGAC_AUTHLOG] as na WHERE na.TerminalID = 1 AND Convert(char(10),na.TransactionTime, 103) = Convert(char(10),pna.TransactionTime, 103) AND na.UserID = pna.UserID )
ELSE  convert(datetime,Convert(char(10),pna.TransactionTime, 103) + ' 08:00:00')
END
      ,MarkExit = 
CASE WHEN 
(SELECT MAX(TransactionTime) FROM [NGAC_AUTHLOG] as na WHERE na.TerminalID = 2 AND Convert(char(10),na.TransactionTime, 103) = Convert(char(10),pna.TransactionTime, 103) AND na.UserID = pna.UserID ) IS NOT NULL
THEN 
(SELECT MAX(TransactionTime) FROM [NGAC_AUTHLOG] as na WHERE na.TerminalID = 2 AND Convert(char(10),na.TransactionTime, 103) = Convert(char(10),pna.TransactionTime, 103) AND na.UserID = pna.UserID )
ELSE convert(datetime,Convert(char(10),pna.TransactionTime, 103) + ' 20:00:00')
END
      ,TimeHere = 
Convert(char(8),
CASE WHEN 
(SELECT MAX(TransactionTime) FROM [NGAC_AUTHLOG] as na WHERE na.TerminalID = 2 AND Convert(char(10),na.TransactionTime, 103) = Convert(char(10),pna.TransactionTime, 103) AND na.UserID = pna.UserID ) IS NOT NULL
THEN 
(SELECT MAX(TransactionTime) FROM [NGAC_AUTHLOG] as na WHERE na.TerminalID = 2 AND Convert(char(10),na.TransactionTime, 103) = Convert(char(10),pna.TransactionTime, 103) AND na.UserID = pna.UserID )
ELSE convert(datetime,Convert(char(10),pna.TransactionTime, 103) + ' 20:00:00')
END - 
CASE WHEN 
(SELECT MIN(TransactionTime) FROM [NGAC_AUTHLOG] as na WHERE na.TerminalID = 1 AND Convert(char(10),na.TransactionTime, 103) = Convert(char(10),pna.TransactionTime, 103) AND na.UserID = pna.UserID ) IS NOT NULL
THEN 
(SELECT MIN(TransactionTime) FROM [NGAC_AUTHLOG] as na WHERE na.TerminalID = 1 AND Convert(char(10),na.TransactionTime, 103) = Convert(char(10),pna.TransactionTime, 103) AND na.UserID = pna.UserID )
ELSE  convert(datetime,Convert(char(10),pna.TransactionTime, 103) + ' 08:00:00')
END
, 14)
  FROM NGAC_AUTHLOG as pna
  GROUP BY pna.UserID, Convert(char(10),pna.TransactionTime, 103)

但在我的查询中,我只知道UserID的第一个入口和最后一个出口,但他每天可以有很多标记。

(我使用MIN和MAX,但这样只显示一个大标记,合并当天的所有标记)

2 个答案:

答案 0 :(得分:1)

尝试这样的事情。第一个联合部分匹配出口和孤儿入口的所有记录。工会的第二部分处理孤立的退出记录。

解决方案1:

SELECT *, Convert(char(8), MarkExit - MarkEntrance, 14) TimeHere
FROM
(
SELECT
    A.UserID, A.TransactionTime MarkEntrance, ISNULL(ExitTime, DateAdd(hh, 20, CONVERT(VARCHAR(10), A.TransactionTime, 101))) MarkExit 
FROM NGAC_AUTHLOG A
OUTER APPLY
(
SELECT MIN(TransactionTime) ExitTime
  FROM NGAC_AUTHLOG B
  WHERE B.TerminalID = 2
  AND B.UserID = A.UserID
  AND B.TransactionTime > A.TransactionTime
) B
WHERE A.TerminalID = 1

UNION ALL

--This looks for orphan Exit Record
SELECT A.UserID, DateAdd(hh, 8, CONVERT(VARCHAR(10), max(A.TransactionTime), 101)), max(A.TransactionTime)
FROM NGAC_AUTHLOG A
WHERE A.TerminalID = 2 
AND EXISTS
    (SELECT 1 
    FROM
       (SELECT UserID, CONVERT(VARCHAR(10), TransactionTime, 101) T2Date, COUNT(*) T2Count
       FROM NGAC_AUTHLOG
       WHERE TerminalID = 2
       GROUP BY UserID, CONVERT(VARCHAR(10), TransactionTime, 101)) X
       LEFT JOIN
       (SELECT UserID, CONVERT(VARCHAR(10), TransactionTime, 101) T1Date, COUNT(*) T1Count
       FROM NGAC_AUTHLOG
       WHERE TerminalID = 1
       GROUP BY UserID, CONVERT(VARCHAR(10), TransactionTime, 101)) Y
          ON X.UserID = Y.UserID
          AND X.T2Date = Y.T1Date
    WHERE X.T2Count > ISNULL(Y.T1Count,0)
    AND X.UserID = A.UserID
    AND X.T2Date = CONVERT(VARCHAR(10), TransactionTime, 101)
    )
GROUP BY A.UserID, CONVERT(VARCHAR(10), TransactionTime, 101)
) X

解决方案2: 假设有一个孤儿退出记录,那个用户当天只有1个退出记录

SELECT *, Convert(char(8), MarkExit - MarkEntrance, 14) TimeHere
FROM
(
SELECT
    A.UserID, A.TransactionTime MarkEntrance, ISNULL(ExitTime, DateAdd(hh, 20, CONVERT(VARCHAR(10), A.TransactionTime, 101))) MarkExit 
FROM NGAC_AUTHLOG A
OUTER APPLY
(
SELECT MIN(TransactionTime) ExitTime
  FROM NGAC_AUTHLOG B
  WHERE B.TerminalID = 2
  AND B.UserID = A.UserID
  AND B.TransactionTime > A.TransactionTime
) B
WHERE A.TerminalID = 1

UNION ALL
--This looks for orphan Exit Record
SELECT A.UserID, DateAdd(hh, 8, CONVERT(VARCHAR(10), A.TransactionTime, 101)), A.TransactionTime
FROM NGAC_AUTHLOG A
WHERE A.TerminalID = 2 
AND NOT EXISTS
    (SELECT 1 
    FROM NGAC_AUTHLOG B
    WHERE B.TerminalID = 1
     AND A.UserID = B.UserID
      AND CONVERT(VARCHAR(10), A.TransactionTime, 101) = CONVERT(VARCHAR(10), B.TransactionTime, 101))  
) X

SQL Fiddle

答案 1 :(得分:0)

尝试这样的事情。注意我还没有运行查询,所以可能会出现一个简单的语法错误(主要是转换 - 真的不确定),如果有问题,请在评论中告诉我。

;WITH minEntranceInDay as(
    SELECT MIN(transactionTime) EntranceTime,Convert(DateTime( Convert(char(10),na.TransactionTime)), 103) Day, UserId    
    FROM NGAC_AUTHLOG WHERE TerminalId = 1
    GROUP BY Convert(DateTime( Convert(char(10),na.TransactionTime)), 103), UserId
), maxExitInDay as(
    SELECT MAX(transactionTime) ExitTime, Convert(DateTime( Convert(char(10),na.TransactionTime)) Day, UserId    
    FROM NGAC_AUTHLOG WHERE TerminalId = 2
    GROUP BY Convert(DateTime( Convert(char(10),na.TransactionTime)), 103), UserId
), usersAndDates as(
    SELECT DISTINCT Convert(DateTime( Convert(char(10),na.TransactionTime))  Day, UserId    
    FROM NGAC_AUTHLOG 
), GroupedData As (
    SELECT ud.UserId, COALESCE(me.minEntranceInDay,Dateadd(h,8,ud.Day)) EntranceTime, COALESCE(mx.maxExitInDay,Dateadd(h,20,ud.Day)) ExitDate
    FROM usersAndDates ud 
    LEFT JOIN minEntranceInDay me ON me.UserId = ud.UserId AND me.Day = ud.Day 
    LEFT JOIN maxExitInDay mx ON mx.UserId = ud.UserId AND mx.Day = ud.Day
)
SELECT *, DATEDIFF(h,EntranceTime,ExitTime)+":"+DATEDIFF(m,EntranceTime,ExitTime)+":"+DATEDIFF(s,EntranceTime,ExitTime) TimeHere
FROM GroupedData