Промежуточный итог по отношению к другому столбцу в SQL Server - PullRequest
0 голосов
/ 04 ноября 2018

У меня есть таблица с именами и датами, которые представляют сотрудников и даты их работы. Я хотел бы подвести итоговое количество дней, в течение которых они работали, и если есть разрыв в непрерывности, то я хотел бы отметить, сколько времени длился перерыв, прежде чем они вернулись к работе.

Вот фактические данные:

+------+---------------------+
| Name |        Date         |
+------+---------------------+
| Adam | 01/01/2018 00:00:00 |
| Adam | 02/01/2018 00:00:00 |
| Adam | 03/01/2018 00:00:00 |
| Adam | 15/01/2018 00:00:00 |
| Ben  | 02/01/2018 00:00:00 |
| Ben  | 03/01/2018 00:00:00 |
+------+---------------------+

А вот и ожидаемые результаты:

+------+---------------------+------------------+---------+
| Name |        Date         | Consecutive_days | Holiday |
+------+---------------------+------------------+---------+
| Adam | 01/01/2018 00:00:00 |                1 |       0 |
| Adam | 02/01/2018 00:00:00 |                2 |       0 |
| Adam | 03/01/2018 00:00:00 |                3 |       0 |
| Adam | 15/01/2018 00:00:00 |                1 |      12 |
| Ben  | 02/01/2018 00:00:00 |                1 |       0 |
| Ben  | 03/01/2018 00:00:00 |                2 |       0 |
+------+---------------------+------------------+---------+

Я знаю, что должен использовать предложение SUM() OVER(ORDER BY Date), если у меня есть различия между последовательными днями, но мне сложно понять, как получить эти различия.

1 Ответ

0 голосов
/ 04 ноября 2018

Я думаю, вы хотите что-то вроде

CREATE TABLE T
    ([Name] varchar(4), [Date] datetime, [Consecutive_days] int);

INSERT INTO T
    ([Name], [Date], [Consecutive_days])
VALUES
    ('Adam', '2018-01-01 00:00:00', 1),
    ('Adam', '2018-01-02 00:00:00', 2),
    ('Adam', '2018-01-03 00:00:00', 3),
    ('Adam', '2018-01-15 00:00:00', 1),
    ('Ben', '2018-01-02 00:00:00', 1),
    ('Ben', '2018-01-03 00:00:00', 2);

WITH C AS
(
SELECT *,
       LAG([Date], 1, 0) OVER(ORDER BY [Date]) L
FROM T
)
SELECT Name,
       [Date],
       Consecutive_days,
       CASE WHEN DATEDIFF(Day, L, [Date]) > 1
                 AND
                 DATEDIFF(Day, L, [Date]) < 360
                 THEN
            DATEDIFF(Day, L, [Date])
            ELSE
            0 END Holiday

FROM C
ORDER BY Name;

Возвращает:

+------+---------------------+------------------+---------+
| Name |        Date         | Consecutive_days | Holiday |
+------+---------------------+------------------+---------+
| Adam | 01/01/2018 00:00:00 |                1 |       0 |
| Adam | 02/01/2018 00:00:00 |                2 |       0 |
| Adam | 03/01/2018 00:00:00 |                3 |       0 |
| Adam | 15/01/2018 00:00:00 |                1 |      12 |
| Ben  | 02/01/2018 00:00:00 |                1 |       0 |
| Ben  | 03/01/2018 00:00:00 |                2 |       0 |
+------+---------------------+------------------+---------+

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

Вы можете сделать это как

SELECT Name + ' has works ' + CAST(SUM(Consecutive_days) AS VARCHAR(10))+
                ' days, and '+
                CAST(SUM(Holiday) AS VARCHAR(10))+
                ' holidays' Result
FROM T
GROUP BY Name;

Возвращает:

+----------------------------------------+
|                 Result                 |
+----------------------------------------+
| Adam has works 7 days, and 12 holidays |
| Ben has works 3 days, and 0 holidays   |
+----------------------------------------+

Обновления в соответствии с вашим комментарием

CREATE TABLE T
    ([Name] varchar(4), [Date] datetime);

INSERT INTO T
    ([Name], [Date])
VALUES
    ('Adam', '2018-01-01 00:00:00'),
    ('Adam', '2018-01-02 00:00:00'),
    ('Adam', '2018-01-03 00:00:00'),
    ('Adam', '2018-01-15 00:00:00'),
    ('Ben', '2018-01-02 00:00:00'),
    ('Ben', '2018-01-03 00:00:00');

SELECT T1.*,
       CASE WHEN
                 DATEDIFF(Day, X.[Date], T1.[Date]) > 1 THEN 1 
            ELSE
                 ROW_NUMBER() OVER (PARTITION BY Name ORDER BY Name)
            END Consecutive_days,
       CASE WHEN DATEDIFF(Day, X.[Date], T1.[Date]) IS NULL
                 OR
                 DATEDIFF(Day, X.[Date], T1.[Date]) = 1
                 THEN 0
                 ELSE
                 DATEDIFF(Day, X.[Date], T1.[Date])
                 END

FROM T T1 OUTER APPLY
(
SELECT TOP 1 [Date] 
FROM T T2 
WHERE T2.[Date] < T1.[Date] 
ORDER BY T2.[Date] DESC
) X;

Возвращает:

+------+---------------------+------------------+---------+
| Name |        Date         | Consecutive_days | Holiday |
+------+---------------------+------------------+---------+
| Adam | 01/01/2018 00:00:00 |                1 |       0 |
| Adam | 02/01/2018 00:00:00 |                2 |       0 |
| Adam | 03/01/2018 00:00:00 |                3 |       0 |
| Adam | 15/01/2018 00:00:00 |                1 |      12 |
| Ben  | 02/01/2018 00:00:00 |                1 |       0 |
| Ben  | 03/01/2018 00:00:00 |                2 |       0 |
+------+---------------------+------------------+---------+
...