【问题标题】:SQL to arrange calculate times as per given conditionsSQL根据给定条件安排计算时间
【发布时间】:2014-09-20 19:00:02
【问题描述】:

我有以下架构和数据:

IF NOT EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[EntryExitLogs]') AND type in (N'U'))
BEGIN
CREATE TABLE [dbo].[EntryExitLogs](
    [DeviceLogId] [int] NOT NULL,
    [EmployeeCode] [nvarchar](50) NOT NULL,
    [LogDate] [datetime] NOT NULL,
    [Direction] [nvarchar](255) NOT NULL,
 CONSTRAINT [PK_EntryExitLogs] PRIMARY KEY CLUSTERED 
(
    [EmployeeCode] ASC,
    [LogDate] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
END
GO

INSERT INTO [dbo].[EntryExitLogs]([DeviceLogId],[EmployeeCode],[LogDate],[Direction]) VALUES('435859','30032','2014-01-21 07:04:41','in');
INSERT INTO [dbo].[EntryExitLogs]([DeviceLogId],[EmployeeCode],[LogDate],[Direction]) VALUES('438019','30032','2014-01-21 08:59:09','out');
INSERT INTO [dbo].[EntryExitLogs]([DeviceLogId],[EmployeeCode],[LogDate],[Direction]) VALUES('441564','30032','2014-01-21 16:57:35','in');
INSERT INTO [dbo].[EntryExitLogs]([DeviceLogId],[EmployeeCode],[LogDate],[Direction]) VALUES('441263','30032','2014-01-21 19:09:19','out');
INSERT INTO [dbo].[EntryExitLogs]([DeviceLogId],[EmployeeCode],[LogDate],[Direction]) VALUES('441264','30032','2014-01-21 19:10:20','in');
INSERT INTO [dbo].[EntryExitLogs]([DeviceLogId],[EmployeeCode],[LogDate],[Direction]) VALUES('439928','34035','2014-01-21 08:29:59','in');
INSERT INTO [dbo].[EntryExitLogs]([DeviceLogId],[EmployeeCode],[LogDate],[Direction]) VALUES('437962','34035','2014-01-21 08:30:12','in');
INSERT INTO [dbo].[EntryExitLogs]([DeviceLogId],[EmployeeCode],[LogDate],[Direction]) VALUES('437992','34035','2014-01-21 08:47:33','out');
INSERT INTO [dbo].[EntryExitLogs]([DeviceLogId],[EmployeeCode],[LogDate],[Direction]) VALUES('440203','34035','2014-01-21 13:38:56','out');
INSERT INTO [dbo].[EntryExitLogs]([DeviceLogId],[EmployeeCode],[LogDate],[Direction]) VALUES('442858','34035','2014-01-21 16:34:08','in');
INSERT INTO [dbo].[EntryExitLogs]([DeviceLogId],[EmployeeCode],[LogDate],[Direction]) VALUES('442860','34035','2014-01-21 16:35:11','out');
INSERT INTO [dbo].[EntryExitLogs]([DeviceLogId],[EmployeeCode],[LogDate],[Direction]) VALUES('441283','34035','2014-01-21 19:16:58','out');

我编写了 SQL 来计算进出时间,如下所示:

;WITH cte AS (
                 SELECT ROW_NUMBER() OVER(
                            PARTITION BY lt.EmployeeCode ORDER BY lt.EmployeeCode,
                            lt.LogDate
                        )              AS RowNo,
                        lt.DeviceLogId,
                        lt.EmployeeCode,
                        lt.LogDate,
                        lt.Direction
                 FROM   EntryExitLogs     lt
             )
SELECT i.EmployeeCode,
       i.LogDate AS InTime,
       (
           SELECT MIN(o.LogDate)
           FROM   cte AS o
           WHERE  o.EmployeeCode = i.EmployeeCode
                  AND o.RowNo = (i.RowNo + 1)
                  AND o.Direction = 'out'
       )    AS OutTime
FROM   cte  AS i
WHERE  i.Direction = 'in'
ORDER BY i.EmployeeCode, i.LogDate

我得到了输出(但不是我想要的),但我希望以以下方式输出(提供 cmets 以获得关于每一行的更多信息):

EmployeeCode InTime             OutTime                 Comments
30032   21-Jan-2014 07:04:41    21-Jan-2014 08:59:09    
30032   21-Jan-2014 16:57:35    21-Jan-2014 19:09:19    
30032   21-Jan-2014 19:10:20    NULL                    If no OUT is specified for the last IN then it should be NULL
34035   21-Jan-2014 08:29:59    21-Jan-2014 13:38:56    Earliest IN and Latest OUT to be taken in case of multiple IN & OUT
34035   21-Jan-2014 16:34:08    21-Jan-2014 19:16:58    Earliest IN and Latest OUT to be taken in case of multiple IN & OUT

请找到此here 的架构

请帮助我实现这一目标。

【问题讨论】:

    标签: tsql sql-server-2005


    【解决方案1】:

    这应该可行:

    ;WITH TrueOut AS --select only the latest "out" in between two "ins"
    (
    SELECT *
    FROM EntryExitLogs a 
    WHERE direction='out'
    AND 
    ISNULL((SELECT MIN(LogDate) FROM EntryExitLogs b 
    WHERE a.EmployeeCode=b.Employeecode
    AND b.direction='out'
    AND b.LogDate>a.LogDate),'9999-12-31')
    >=
    ISNULL((SELECT MIN(LogDate) FROM EntryExitLogs b 
    WHERE a.EmployeeCode=b.Employeecode
    AND b.direction='in'
    AND b.LogDate>a.LogDate),'9999-12-31')
    ),
    TrueIn AS --select only the earlies "in" in between two "outs"
    (
    SELECT *
    FROM EntryExitLogs a 
    WHERE direction='in'
    AND 
    ISNULL((SELECT MAX(LogDate) FROM EntryExitLogs b 
    WHERE a.EmployeeCode=b.Employeecode
    AND b.direction='out'
    AND b.LogDate<a.LogDate),'1900-01-01')
    >=
    ISNULL((SELECT MAX(LogDate) FROM EntryExitLogs b 
    WHERE a.EmployeeCode=b.Employeecode
    AND b.direction='in'
    AND b.LogDate<a.LogDate),'1900-01-01')
    )
    -- For every in select the next out
    SELECT a.EmployeeCode, a.LogDate InTime, 
    (SELECT MIN(LogDate) 
    FROM TrueOut b
    WHERE a.EmployeeCode=b.EmployeeCode
    AND a.LogDate<b.LogDate) OutTIme
    FROM TrueIn a
    

    【讨论】:

    • 没有这样的标准,在这个例子中没有显示。我需要相邻 IN - OUT 对的最早输入和最晚输出。
    • @Nagesh 我已编辑答案与最初的概念基本相同,但事先清除了连续进/出时间。
    • 亲爱的@Jayvee 感谢您抽出宝贵时间。是的,您的解决方案符合我的要求。我将对此进行测试(也用于性能),如果有问题会通知您。再次感谢您的努力。
    猜你喜欢
    • 1970-01-01
    • 2023-01-08
    • 2020-03-26
    • 2019-06-10
    • 1970-01-01
    • 2020-06-02
    • 1970-01-01
    • 1970-01-01
    • 2020-07-03
    相关资源
    最近更新 更多