2013-09-25 52 views
1

在SQL 2000我有一個包含以下內容的表:查找連續工作日期爲每個員工

ID Date WorkingTime EmployeeID 

八月,該表將包含200名員工,8/1日期 - 8/31。我需要找出每位員工在上班和下班的第一天開始工作時間連續5天的最短日期。

例如: 如果僱員123看起來如下和2013年8月10日被通過在:

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開始,因爲這是傳遞到查詢中的日期。這張桌子在現實生活中非常龐大,並且包含許多日期和員工,而不僅限於八月。我想過使用光標來瀏覽所有這些,但我認爲這會非常慢。我也在考慮把所有的工作時間都加到臨時表中,然後在他們身上做一個日期,以找到連續的5,其中的日期是1,但我不太確定如何執行。有沒有更好的方法我沒有想到?

+4

真的使用SQL Server 2000? :( –

+0

尋找一個WorkingTime = 5的總和可能是解決方案的一部分 –

+0

@Goat CO,告訴我一下吧 – mameesh

回答

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; 
1

下面的查詢將爲您想要達到的目標提供良好的開端,根據您的表格修改架構。

SQL小提琴

@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