Как получить разницу во времени Итоговые значения длительности, сгруппированные по имени и когда значение изменяется определенным образом? - PullRequest
0 голосов
/ 14 февраля 2020

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

Пример данных для одного имени, но в реальных данных много разных Имен.

+--------+---------------+---------------------+--------+
| RowNum |     Name      |      Timestamp      | Value  |
+--------+---------------+---------------------+--------+
|      1 | D1_HS_308_ALM | 2020-02-10 11:55:00 | 0      |
|      2 | D1_HS_308_ALM | 2020-02-10 11:51:00 | 0      |
|      3 | D1_HS_308_ALM | 2020-02-10 11:49:00 | NULL   |
|      4 | D1_HS_308_ALM | 2020-02-10 11:46:00 | 1      |
|      5 | D1_HS_308_ALM | 2020-02-10 08:02:00 | 0      |
|      6 | D1_HS_308_ALM | 2020-02-10 08:02:00 | NULL   |
|      7 | D1_HS_308_ALM | 2020-02-10 08:02:00 | 0      |
|      8 | D1_HS_308_ALM | 2020-02-10 07:56:00 | 1      |
|      9 | D1_HS_308_ALM | 2020-02-10 07:51:00 | 1      |
|     10 | D1_HS_308_ALM | 2020-02-10 07:50:00 | 0      |
+--------+---------------+---------------------+--------+

Эти данные должны возвращать 11 минут для перехода 9 -> 7 строк и 5 минут для перехода 4 -> 2 строк; всего 16 минут для этого Имени.

Я не уверен, как это сделать sh, когда не гарантируется, что в следующей строке будет правильное изменение значения - иногда это будет несколько или много строк позже.

Ответы [ 3 ]

2 голосов
/ 14 февраля 2020
DECLARE @myTable TABLE
(
    RowNum INT,
    Name VARCHAR(20),
    [Timestamp] DATETIME,
    Value INT
);

INSERT INTO @myTable
(
    RowNum,
    Name,
    [Timestamp],
    Value
)
VALUES
(1, 'D1_HS_308_ALM', '2020-02-10 11:55:00', 0),
(2, 'D1_HS_308_ALM', '2020-02-10 11:51:00', 0),
(3, 'D1_HS_308_ALM', '2020-02-10 11:49:00', NULL),
(4, 'D1_HS_308_ALM', '2020-02-10 11:46:00', 1),
(5, 'D1_HS_308_ALM', '2020-02-10 08:02:00', 0),
(6, 'D1_HS_308_ALM', '2020-02-10 08:02:00', NULL),
(7, 'D1_HS_308_ALM', '2020-02-10 08:02:00', 0),
(8, 'D1_HS_308_ALM', '2020-02-10 07:56:00', 1),
(9, 'D1_HS_308_ALM', '2020-02-10 07:51:00', 1),
(10, 'D1_HS_308_ALM', '2020-02-10 07:50:00', 0);

SELECT *,
       DATEDIFF(MINUTE, tStart, tEnd) AS duration
FROM
(
    SELECT t1.Name,
           MIN(t1.RowNum) AS rStart,
           MIN(t1.Timestamp) AS tStart,
           t.rNo AS rEnd,
           t.tEnd
    FROM @myTable t1
        OUTER APPLY
    (
        SELECT TOP (1)
               t2.RowNum,
               t2.Timestamp
        FROM @myTable t2
        WHERE t1.Name = t2.Name
              AND t2.Timestamp > t1.Timestamp
              AND t2.Value = 0
        ORDER BY t2.Timestamp
    ) t(rNo, tEnd)
    WHERE t1.Value = 1
    GROUP BY t1.Name,
             t.rNo,
             t.tEnd
) tmp;

Обновление:

SELECT Name,
       Sum(DATEDIFF(MINUTE, tStart, tEnd)) AS duration
FROM
(
    SELECT t1.Name,
           MIN(t1.Timestamp) AS tStart,
           t.tEnd
    FROM @myTable t1
        OUTER APPLY
    (
        SELECT TOP (1)
               t2.Timestamp
        FROM @myTable t2
        WHERE t1.Name = t2.Name
              AND t2.Timestamp > t1.Timestamp
              AND t2.Value = 0
        ORDER BY t2.Timestamp
    ) t(tEnd)
    WHERE t1.Value = 1
    GROUP BY t1.Name,
             t.tEnd
) tmp
group by name;
1 голос
/ 14 февраля 2020

Вы можете использовать оконные функции:

  • min(), чтобы условно получить следующую метку времени со значением 0.
  • lag(), чтобы увидеть предыдущее значение.

Затем отфильтруйте до перехода от 0 до 1 и выполните некоторую арифметику даты c:

select t.*,
       datediff(seconds, timestamp, next_ts_0) as duration
from (select t.*,
             min(case when value = 0 then timestamp end) over (partition by name order by timestamp desc) as next_ts_0,
             lag(value) over (partition by name order by timestamp) as prev_value
      from t.*
     ) t
where (prev_value = 0 or prev_value is null) and value = 1
0 голосов
/ 14 февраля 2020

Только что изменил запрос на выборку Cetin в соответствии с вашими потребностями:

DECLARE @myTable TABLE
(
    RowNum INT,
    Name VARCHAR(20),
    [Timestamp] DATETIME,
    Value INT
);

INSERT INTO @myTable
(
    RowNum,
    Name,
    [Timestamp],
    Value
)
VALUES
(1, 'D1_HS_308_ALM', '2020-02-10 11:55:00', 0),
(2, 'D1_HS_308_ALM', '2020-02-10 11:51:00', 0),
(3, 'D1_HS_308_ALM', '2020-02-10 11:49:00', NULL),
(4, 'D1_HS_308_ALM', '2020-02-10 11:46:00', 1),
(5, 'D1_HS_308_ALM', '2020-02-10 08:02:00', 0),
(6, 'D1_HS_308_ALM', '2020-02-10 08:02:00', NULL),
(7, 'D1_HS_308_ALM', '2020-02-10 08:02:00', 0),
(8, 'D1_HS_308_ALM', '2020-02-10 07:56:00', 1),
(9, 'D1_HS_308_ALM', '2020-02-10 07:51:00', 1),
(10, 'D1_HS_308_ALM', '2020-02-10 07:50:00', 0);


SELECT tmp.Name,
       SUM(DATEDIFF(MINUTE, tStart, tEnd)) AS duration
FROM
(
    SELECT t1.Name,
           --MIN(t1.RowNum) AS rStart,
           MIN(t1.Timestamp) AS tStart,
           --t.rNo AS rEnd,
           t.tEnd
    FROM @myTable t1
        OUTER APPLY
    (
        SELECT TOP (1)
               --t2.RowNum,
               t2.Timestamp
        FROM @myTable t2
        WHERE t1.Name = t2.Name
              AND t2.Timestamp > t1.Timestamp
              AND t2.Value = 0
        ORDER BY t2.Timestamp
    --) t(rNo, tEnd)
    ) t(tEnd)
    WHERE t1.Value = 1
    GROUP BY t1.Name,
             --t.rNo,
             t.tEnd
) tmp
GROUP BY tmp.Name;
...