在SQL 2000中,我有一个包含以下内容的表:
ID Date WorkingTime EmployeeID
8月份,该表格将包含200名员工,日期为8/1 - 8/31。我需要找出每个员工从过去一天开始到后退的连续工作时间前5天的最短日期。
例如: 如果员工123看起来如下并且通过了8/10/2013:
ID Date WorkingTime EmployeeID
1 8/1 1 123
2 8/2 0 123
3 8/3 0 123
4 8/4 1 123
5 8/5 1 123
6 8/6 1 123
7 8/7 1 123
8 8/8 1 123
9 8/9 0 123
10 8/10 1 123
结果将是8/4。这需要对表中的所有员工一次性完成,因此他们都会有不同的最短日期,所有这些日期都从8/10开始,因为那是传递给查询的日期。这张桌子在现实生活中非常大,并且包含许多日期和员工,而不仅仅是在Auguest。我想过使用游标来完成所有这些但是我认为这会非常慢。我还考虑将所有工作时间添加到临时表并对其进行约会,以找到具有1的日期值的连续5,但我不太确定如何执行它。有没有更好的方式我没想到?
答案 0 :(得分:1)
下面的查询将为您想要实现的目标提供良好的开端,并根据您的表修改架构。
SQL小提琴demo
@DateToPull - 您要为其提取数据的日期。
#TimeSheet是你原来的表
#SubsetTimeSheet - 包含来自#TimeSheet表的记录子集的表。填写了从月初到过去的记录。
注意:使用较新版本的SQL Server可以更有效地编写此查询。
declare @DateToPull datetime
select @DateToPull = '08/10/2013'
if object_id('tempdb..#TimeSheet') is not null
drop table #TimeSheet
create table #TimeSheet
(
ID int identity(1, 1),
EmployeeID int,
[WorkDate] datetime,
WorkingTime bit
)
insert into #TimeSheet(EmployeeID, [WorkDate], WorkingTime)
select 123 , '08/01/2013', 0
union all
select 123 , '08/02/2013', 1
union all
select 123 , '08/03/2013', 0
union all
select 123 , '08/04/2013', 1
union all
select 123 , '08/05/2013', 1
union all
select 123 , '08/06/2013', 1
union all
select 123 , '08/07/2013', 1
union all
select 123 , '08/08/2013', 1
union all
select 123 , '08/09/2013', 0
union all
select 123 , '08/10/2013', 1
union all
select 123 , '08/11/2013', 1
union all
select 123 , '08/12/2013', 1
union all
select 123 , '08/13/2013', 1
union all
select 123 , '08/14/2013', 1
union all
select 123 , '08/15/2013', 0
union all
select 123 , '08/16/2013', 1
union all
select 123 , '08/17/2013', 1
union all
select 123 , '08/18/2013', 1
union all
select 123 , '08/19/2013', 1
union all
select 123 , '08/20/2013', 1
if object_id('tempdb..#SubsetTimeSheet') is not null
drop table #SubsetTimeSheet
create table #SubsetTimeSheet
(
EmployeeID int,
[WorkDate] datetime,
WorkingTime bit
)
insert into #SubsetTimeSheet(EmployeeID, [WorkDate], WorkingTime)
select EmployeeID, [WorkDate], WorkingTime
from #TimeSheet
where
datediff(dd, [WorkDate], @DateToPull) >= 0
and datediff(dd, DATEADD(dd, -(DAY(@DateToPull)-1), @DateToPull), [WorkDate]) >= 0
and WorkingTime = 1
order by
EmployeeID,
[WorkDate] desc
select A.EmployeeID, max(E.WorkDate) WorkDate
from
#SubsetTimeSheet A
inner join #SubsetTimeSheet B on datediff(dd, A.[WorkDate] - 1, B.WorkDate) = 0 and A.EmployeeID = B.EmployeeID
inner join #SubsetTimeSheet C on datediff(dd, A.[WorkDate] - 2, C.WorkDate) = 0 and A.EmployeeID = C.EmployeeID
inner join #SubsetTimeSheet D on datediff(dd, A.[WorkDate] - 3, D.WorkDate) = 0 and A.EmployeeID = D.EmployeeID
inner join #SubsetTimeSheet E on datediff(dd, A.[WorkDate] - 4, E.WorkDate) = 0 and A.EmployeeID = E.EmployeeID
group by
A.EmployeeID
答案 1 :(得分:1)
DECLARE @MyTable TABLE
(
ID INT IDENTITY PRIMARY KEY,
[Date] SMALLDATETIME NOT NULL,
WorkingTime INT NOT NULL,
EmployeeID INT NOT NULL
);
INSERT @MyTable ([Date], WorkingTime, EmployeeID)
-- First employee
SELECT '20130801', 1, 123 UNION ALL
SELECT '20130802', 0, 123 UNION ALL
SELECT '20130803', 0, 123 UNION ALL
SELECT '20130804', 1, 123 UNION ALL
SELECT '20130805', 1, 123 UNION ALL
SELECT '20130806', 1, 123 UNION ALL
SELECT '20130807', 1, 123 UNION ALL
SELECT '20130808', 1, 123 UNION ALL
SELECT '20130809', 0, 123 UNION ALL
SELECT '20130810', 1, 123 UNION ALL
-- Second employee
SELECT '20130801', 1, 126 UNION ALL
SELECT '20130802', 1, 126 UNION ALL
SELECT '20130803', 1, 126 UNION ALL
SELECT '20130804', 1, 126 UNION ALL
SELECT '20130805', 1, 126 UNION ALL
SELECT '20130806', 0, 126 UNION ALL
-- Third employee
SELECT '20130801', 0, 127 UNION ALL
SELECT '20130802', 0, 127 UNION ALL
SELECT '20130803', 1, 127 UNION ALL
SELECT '20130804', 1, 127 UNION ALL
SELECT '20130805', 0, 127 UNION ALL
SELECT '20130806', 0, 127;
-
DECLARE @Results TABLE
(
EmployeeID INT NOT NULL,
DaysDiff INT NOT NULL,
PRIMARY KEY(EmployeeID, DaysDiff), -- This is a "clustered index"/index organized table
RowNum INT IDENTITY NOT NULL,
[Date] SMALLDATETIME NOT NULL
);
INSERT @Results (EmployeeID, DaysDiff, [Date])
SELECT x.EmployeeID,
DATEDIFF(DAY, 0, x.[Date]) AS DaysDiff,
x.[Date]
FROM @MyTable x
WHERE x.WorkingTime = 1
/*
This ORDER BY clause and the clustered index (PRIMARY KEY(EmployeeID, DaysDiff))
should give a hint to SQL Server so that
RowNum IDENTITY values will be generated in this order: EmployeeID, DaysDiff
Note #1: There is not 100% guarantee that insert order will be the same as
ORDER BY x.EmployeeID, DaysDiff
and
clustered index key (EmployeeID, DaysDiff)
Note #2: This INSERT INTO table with identity column simulates the ROW_NUMBER function
which is available starting with SQL2005.
*/
ORDER BY x.EmployeeID, DaysDiff
OPTION (MAXDOP 1); -- It minimizes the risk of messing up the order of RowNum
SELECT y.EmployeeID, MAX(y.GroupStartDate) AS FirstGroupStartDate
FROM
(
SELECT x.EmployeeID, x.GroupID,
MIN(x.[Date]) AS GroupStartDate, MAX(x.[Date]) AS GroupEndDate,
DATEDIFF(DAY, MIN(x.[Date]), MAX(x.[Date]))+1 AS ContinuousDays
FROM
(
SELECT *, r.DaysDiff - r.RowNum AS GroupID
FROM @Results r
) x
GROUP BY x.EmployeeID, x.GroupID
) y
WHERE y.ContinuousDays > 4
GROUP BY y.EmployeeID;