Как найти людей, которые постоянно отсутствуют в течение n дней? - PullRequest
5 голосов
/ 20 марта 2009

База данных: MS SQL 2005

Таблица:

EmployeeNumber | EntryDate | Состояние

Пример данных:

200 | 01.03.2009 | P
200 | 3/2/2009 | A
200 | 3/3/2009 | A
201 | 01.03.2009 | A
201 | 3/2/2009 | P

Где P присутствует, A отсутствует. Я пробовал row_number над partion. Но он не генерирует последовательность, которую я ожидаю.

Для приведенных выше данных ожидаемая последовательность 1 1 2 1 1

SELECT EmployeeNumber, EntryDate,Status
    ROW_NUMBER() OVER (
    PARTITION BY EmployeeNumber, Status
    ORDER BY EmployeeNumber,EntryDate    ) AS 'RowNumber'
    FROM [Attendance]

Ответы [ 4 ]

3 голосов
/ 20 марта 2009

Я не уверен, что я следую тому, что вы хотите, с последовательностью 1 1 2 1 1, но простое добавление порядка к вашему исходному запросу создает эту последовательность ...

SELECT  EmployeeNumber, 
        EntryDate,
        Status,
        ROW_NUMBER() OVER (PARTITION BY EmployeeNumber, Status ORDER BY EmployeeNumber, EntryDate) AS 'RowNumber'    
FROM    Attendance
ORDER BY EmployeeNumber, EntryDate


/*
EmployeeNumber EntryDate               Status RowNumber
-------------- ----------------------- ------ --------------------
200            2009-03-01 00:00:00     P      1
200            2009-03-02 00:00:00     A      1
200            2009-03-03 00:00:00     A      2
201            2009-03-01 00:00:00     A      1
201            2009-03-02 00:00:00     P      1

(5 row(s) affected)
*/
1 голос
/ 20 марта 2009

Вы должны быть в состоянии сделать это с помощью CTE в SQL 2005. Кража данных Ливенса:

DECLARE @Attendance TABLE (EmployeeNumber INTEGER, EntryDate DATETIME, Status VARCHAR(1))

INSERT INTO @Attendance VALUES (200, '03/01/2009', 'P')
INSERT INTO @Attendance VALUES (200, '03/02/2009', 'A')
INSERT INTO @Attendance VALUES (200, '03/03/2009', 'A')
INSERT INTO @Attendance VALUES (200, '03/04/2009', 'A')
INSERT INTO @Attendance VALUES (200, '04/04/2009', 'A')
INSERT INTO @Attendance VALUES (200, '04/05/2009', 'A')
INSERT INTO @Attendance VALUES (201, '03/01/2009', 'A')
INSERT INTO @Attendance VALUES (201, '03/02/2009', 'A')
INSERT INTO @Attendance VALUES (201, '03/03/2009', 'P');

Затем используйте этот CTE для извлечения последовательности:


 WITH Dates 
    (
        EntryDate,
        EmployeeNumber,
        Status,
        Days
    ) 
    AS
    (
        SELECT
            a.EntryDate,
            a.EmployeeNumber,
            a.Status,
            1
        FROM
            @Attendance a

        WHERE
            a.EntryDate = (SELECT MIN(EntryDate) FROM @Attendance)


        -- RECURSIVE    
        UNION ALL

        SELECT
            a.EntryDate, 
            a.EmployeeNumber,
            a.Status,
            CASE WHEN (a.Status = Parent.Status) THEN Parent.Days + 1 ELSE 1 END
        FROM
            @Attendance a
        INNER JOIN
            Dates parent
        ON
            datediff(day, a.EntryDate, DateAdd(day, 1, parent.EntryDate)) = 0
        AND
            a.EmployeeNumber = parent.EmployeeNumber
    )

    SELECT * FROM Dates order by EmployeeNumber, EntryDate

Хотя в качестве последнего примечания последовательность кажется мне странной, в зависимости от ваших требований может быть лучший способ агрегирования данных? Тем не менее, это произведет последовательность, которую вам требуется

1 голос
/ 20 марта 2009

Вам это помогает?
Он не производит последовательность, которую вы спрашиваете (не знаю, как это сделать), но он дает вам количество дней подряд, когда кто-то отсутствовал.

DECLARE @Attendance TABLE (EmployeeNumber INTEGER, EntryDate DATETIME, Status VARCHAR(1))

INSERT INTO @Attendance VALUES (200, '03/01/2009', 'P')
INSERT INTO @Attendance VALUES (200, '03/02/2009', 'A')
INSERT INTO @Attendance VALUES (200, '03/03/2009', 'A')
INSERT INTO @Attendance VALUES (200, '03/04/2009', 'A')
INSERT INTO @Attendance VALUES (200, '04/04/2009', 'A')
INSERT INTO @Attendance VALUES (200, '04/05/2009', 'A')
INSERT INTO @Attendance VALUES (201, '03/01/2009', 'A')
INSERT INTO @Attendance VALUES (201, '03/02/2009', 'A')
INSERT INTO @Attendance VALUES (201, '03/03/2009', 'P')


SELECT a1.EmployeeNumber, [Absent] = COUNT(*) + 1
FROM @Attendance a1
     INNER JOIN @Attendance a2 ON a1.EntryDate = a2.EntryDate - 1 
                                  AND a1.EmployeeNumber = a2.EmployeeNumber
                                  AND a1.Status = a2.Status
GROUP BY a1.EmployeeNumber
0 голосов
/ 20 марта 2009

Вы можете использовать рекурсию, аналогично тому, что я сделал здесь . Однако кажется, что ваша проблема немного проще, и поскольку SQL Server ограничивает рекурсию до 99, это может не сработать для людей, которые часто отсутствуют. Позвольте мне подумать об этом несколько минут.

Если у вас есть строки на каждый день, присоединяйтесь к Ливену.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...