2013-09-25 3 views
1

В SQL 2000 У меня есть таблица, которая содержит следующее:Найти последовательные рабочие даты для каждого сотрудника

ID Date WorkingTime EmployeeID 

В августе эта таблица будет содержать 200 сотрудников с датами 8/1 - 8/31. Мне нужно выяснить, какова дата MIN для первых 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, так как это была дата, которая была передана в запрос. Эта таблица очень велика в реальной жизни, и она охватывает множество дат и сотрудников, а не только в Аугусте. Я думал об использовании курсора, чтобы пройти все это, но я думаю, что это будет очень медленно. Я также думал о том, чтобы добавить все рабочие времена в временную таблицу и сделать датифик на них, чтобы найти последовательные 5 с датой в 1, но я не был уверен, как это выполнить. Есть ли лучший способ, о котором я не думаю?

+4

Действительно с помощью SQL Server 2000? :( –

+0

Ищете сумму WorkTime = 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