Схема таблицы
CREATE TABLE [dbo].[PunchClock]
(
[Id] [int] IDENTITY(1,1) NOT NULL,
[StaffId] [int] NULL,
[LocationId] [int] NULL,
[PunchIn] [datetime] NOT NULL,
[PunchOut] [datetime] NULL,
[PunchType] [varchar](1) NULL,
[IsApproved] [bit] NOT NULL,
[IsLate] [bit] NOT NULL,
[ApprovedPunchIn] [datetime] NULL,
[ApprovedPunchOut] [datetime] NULL,
[ManagerComments] [nvarchar](100) NULL,
[PunchInComments] [nvarchar](100) NULL,
[PunchOutComments] [nvarchar](100) NULL,
[ApprovedBy] [int] NULL,
[ApprovedOn] [datetime] NULL,
[CompanyId] [int] NULL,
[Deleted] [bit] NOT NULL,
[UpdatedBy] [int] NULL,
[UpdatedOn] [datetime] NULL
) ON [PRIMARY]
GO
SET ANSI_PADDING OFF
GO
ALTER TABLE [dbo].[PunchClock]
ADD DEFAULT ((0)) FOR [IsApproved]
GO
ALTER TABLE [dbo].[PunchClock]
ADD DEFAULT ((0)) FOR [IsLate]
GO
ALTER TABLE [dbo].[PunchClock]
ADD DEFAULT ((0)) FOR [Deleted]
GO
Запрос
SELECT *
FROM
(SELECT
StaffId,
[Date],
PunchIn, PunchOut,
DayOfWeek,
TotalHours,
StaffTotalHour,
ROW_NUMBER() OVER (PARTITION BY [Date] ORDER BY [Date] DESC) AS [Rank],
CAST(CONVERT(varchar, DATEADD(SECOND, SUM(TotalBreakHours) OVER (PARTITION BY Date) * 3600, 0), 108) AS time) AS TotalBreakHours,
CAST(CONVERT(varchar, DATEADD(SECOND, (DATEDIFF(SECOND, CAST(CONVERT(varchar, DATEADD(SECOND, SUM(TotalBreakHours) OVER (PARTITION BY Date) * 3600, 0), 108) AS time), StaffTotalHour) / 3600.0) * 3600, 0), 108) AS time) AS StaffNetHour
FROM
(SELECT
*,
DATENAME(dw, PunchIn) AS [DayOfWeek],
DATEDIFF(SECOND, PunchIn, PunchOut) / 3600.0 AS TotalHours,
0 AS TotalBreakHours,
CAST(CONVERT(varchar, DATEADD(SECOND, (DATEDIFF(SECOND, PunchIn, PunchOut) / 3600.0) * 3600, 0), 108) AS time) AS StaffTotalHour
FROM
(SELECT
StaffID,
Date,
MIN(PunchIn) AS PunchIn,
MAX(PunchOut) AS PunchOut
FROM
(SELECT
StaffID,
CONVERT(date, PunchIn) AS [Date],
CASE
WHEN PunchOut IS NULL THEN DATEADD(SECOND, 1, CAST(CAST(DATEADD(DAY, 0, CONVERT(date, PunchIn)) AS date) AS datetime2))
ELSE PunchIn
END AS PunchIn,
CASE
WHEN PunchOut IS NULL THEN PunchIn
ELSE PunchOut
END AS PunchOut,
PunchType
FROM
(SELECT
StaffID,
PunchIn,
CASE
WHEN CONVERT(date, PunchIn) < CONVERT(date, PunchOut) THEN DATEADD(SECOND, -1, CAST(CAST(DATEADD(DAY, 1, CONVERT(date, PunchIn)) AS date) AS datetime2))
ELSE PunchOut
END AS PunchOut,
PunchType
FROM
PunchClock) tbl1
WHERE
PunchType = 'P') tbl2
GROUP BY
Date, StaffID) dsag
UNION ALL
SELECT *,
DATENAME(dw, PunchIn) AS [DayOfWeek],
0 AS TotalHours,
DATEDIFF(SECOND, PunchIn, PunchOut) / 3600.0 AS TotalBreakHours,
'' AS StaffTotalHour
FROM (SELECT StaffID,
Date,
MIN(PunchIn) AS PunchIn,
MAX(PunchOut) AS PunchOut
FROM (SELECT StaffID,
CONVERT(date, PunchIn) AS [Date],
CASE
WHEN PunchOut IS NULL THEN DATEADD(SECOND, 1, CAST(CAST(DATEADD(DAY, 0, CONVERT(date, PunchIn)) AS date) AS datetime2))
ELSE PunchIn
END AS PunchIn,
CASE WHEN PunchOut IS NULL THEN PunchIn ELSE PunchOut END AS PunchOut,
PunchType
FROM (SELECT StaffID,
PunchIn,
CASE
WHEN CONVERT(date, PunchIn) < CONVERT(date, PunchOut) THEN DATEADD(SECOND, -1, CAST(CAST(DATEADD(DAY, 1, CONVERT(date, PunchIn)) AS date) AS datetime2))
ELSE PunchOut
END AS PunchOut,
PunchType
FROM PunchClock) tbl1
WHERE PunchType = 'B') tbl2
GROUP BY Date,
StaffID) dsag ) tbl23 ) tblMain
WHERE Rank = 1;
РЕЗУЛЬТАТ
Упрощение запроса
Запрос не имеет ошибок или проблем. Он возвращает результаты, которые я хочу, НО проблема в том, что у него много подзапросов, и он не соответствует SQL Стандарту.
Может кто-нибудь упростить это или использовать другой способ получить тот же результат или переписать запрос в более стандартная и простая форма?