我有以下架构和数据:
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
我正在获取输出(但不是我所希望的),但我希望以下列方式输出(注释是针对每一行提供的更多信息):
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
的架构请帮助我实现这一目标。
答案 0 :(得分: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