简体   繁体   中英

Sql total minutes between records

I am trying to make a query that returns me the number of minutes that a person has worked. A person can have many entries and exits the same day. I would like to know the total number of minutes between entry and exit.

Here a picture of the table: 表

For example: I would like for 20498090R to return 79 minutes

I try with this query but it doesn't work well:

SELECT  Empleado,
    DATEDIFF("mi", Hora, NextDate)
FROM    (   SELECT  Empleado,
                Hora,
                (   SELECT  MIN(Hora) 
                    FROM    [dbo].[Fichajes] T2
                    WHERE   T2.Empleado = T1.Empleado 
                    AND     T2.Hora > T1.Hora
                ) AS NextDate
        FROM    [dbo].[Fichajes] T1

    ) AS T 

With this query:

12212332W --> 
20498090R --> 4
41435568N --> 6
20498090R --> 7055
41435568N --> 
20498090R --> 75
20498090R --> 

Create a CTE from the sign-in table that is ordered by the employee and the timestamp, and assigns a row number. Now you can join that CTE to itself to find only the rows where an employee both signed in and signed out. Then you can find the minutes worked, and add them up.

;with cte
as (select f.Empleado, f.Hora, f.Entrada, ROW_NUMBER() over (order by f.Empleado, f.Hora) RowNum
    from Fichajes f)

select c1.Empleado, SUM(DATEDIFF(mi, c1.Hora, c2.Hora)) MinutesWorked
from cte c1
join cte c2 on c2.Empleado = c1.Empleado and c2.RowNum = c1.RowNum + 1 and c1.Entrada = 1 and c2.Entrada = 0
group by c1.Empleado

DEMO

Use Cursers something like this:

DECLARE @LV_EMP_CUR CURSOR
DECLARE @LV_EMP VARCHAR(32)

DECLARE @LV_MINUTES FLOAT

SET @LV_EMP_CUR=CURSOR FOR SELECT Empleado FROM TABLE_NAME

                    OPEN @LV_EMP_CUR FETCH NEXT FROM @LV_EMP_CUR INTO @LV_EMP
WHILE @@FETCH_STATUS = 0
    BEGIN

        DECLARE @DT DATETIME
        SET @DT = (SELECT HORA FROM TABLE_NAME WHERE EMPLEADO=@LV_EMP)

        SET @LV_MINUTES= @LV_MINUTES + SELECT CAST(@DT AS TIME)

        FETCH NEXT FROM @LV_EMP_CUR INTO @LV_EMP
    END
CLOSE @LV_EMP_CUR
DEALLOCATE @LV_EMP_CUR

I have used a sql window function LEAD to find the next record and partitioned by the user and day. Then calculated the working minutes between two times of the same user and of the same date.

Inserted the data into a temp table to Group by and get the total working minutes. You can use SELECT * FROM #tempTime; before the final select query to see the result what goes into the temp table. It gives an idea if the code is working correctly or not.

Final code:

IF OBJECT_ID('dbo.Fichajes') IS NULL 
CREATE TABLE dbo.Fichajes(
    [Empleado] [varchar](20) NULL,
    [Obra] [varchar](20) NULL,
    [Hora] [datetime2](7) NULL,
    [Entrada] [bit] NULL,
    [Motivo] [varchar](20) NULL,
    [Activated] [bit] NULL
) 
;

INSERT [dbo].[Fichajes] ([Empleado], [Obra], [Hora], [Entrada], [Motivo], [Activated]) VALUES (N'12212332W', N'PRY12345', CAST(N'2017-04-17 12:03:00.0000000' AS DateTime2), 1, NULL, NULL)
INSERT [dbo].[Fichajes] ([Empleado], [Obra], [Hora], [Entrada], [Motivo], [Activated]) VALUES (N'20498090R', N'PRY12345', CAST(N'2017-04-20 12:21:00.0000000' AS DateTime2), 1, NULL, NULL)
INSERT [dbo].[Fichajes] ([Empleado], [Obra], [Hora], [Entrada], [Motivo], [Activated]) VALUES (N'20498090R', N'PRY12345', CAST(N'2017-04-20 12:25:00.0000000' AS DateTime2), 0, NULL, NULL)
INSERT [dbo].[Fichajes] ([Empleado], [Obra], [Hora], [Entrada], [Motivo], [Activated]) VALUES (N'41435568N', N'PRY12345', CAST(N'2017-04-20 12:23:00.0000000' AS DateTime2), 1, NULL, NULL)
INSERT [dbo].[Fichajes] ([Empleado], [Obra], [Hora], [Entrada], [Motivo], [Activated]) VALUES (N'41435568N', N'PRY12345', CAST(N'2017-04-20 12:29:00.0000000' AS DateTime2), 0, NULL, NULL)
INSERT [dbo].[Fichajes] ([Empleado], [Obra], [Hora], [Entrada], [Motivo], [Activated]) VALUES (N'20498090R', N'PRY12345', CAST(N'2017-04-25 10:00:00.0000000' AS DateTime2), 1, NULL, NULL)
INSERT [dbo].[Fichajes] ([Empleado], [Obra], [Hora], [Entrada], [Motivo], [Activated]) VALUES (N'20498090R', N'PRY12345', CAST(N'2017-04-25 11:15:00.0000000' AS DateTime2), 0, NULL, NULL)


IF OBJECT_ID('tempdb..#tempTime') IS NOT NULL DROP TABLE #tempTime;
with c1 AS
(
    SELECT 
         [Empleado]
        ,[Obra]
        ,[Entrada]
        ,[Motivo]
        ,[Activated]
        ,CONVERT(date, Hora) AS [Date]
        ,CONVERT(time, Hora, 114) AS [Time]
        ,[Hora] 
    FROM [dbo].[Fichajes]
)
SELECT 
     [Empleado]
    ,[Hora]
    ,LAG( [Hora]) OVER(PARTITION BY [Empleado], [Date] ORDER BY [Empleado], [Hora] ASC) AS PreviousRecord
    ,LEAD( [Hora]) OVER(PARTITION BY [Empleado], [Date] ORDER BY [Empleado], [Hora] ASC) AS NextRecord
    ,DATEDIFF(MINUTE,  [Hora], LEAD( [Hora]) OVER(PARTITION BY [Empleado], [Date] ORDER BY [Empleado], [Hora] ASC)) AS [Minutes]
INTO #tempTime
FROM c1
;

SELECT
    [Empleado]
    ,SUM([Minutes]) AS WorkingMinutes
FROM #tempTime
GROUP BY [Empleado]
;

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM