Эффективный способ кластеризации временной шкалы ИЛИ восстановления номера партии - PullRequest
0 голосов
/ 19 ноября 2018

Я работаю над большим набором данных (150 КБ / день) базы данных тестера.Каждая строка содержит данные о конкретном тесте продукта.Каждый тестер вставляет результаты своего теста.

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

Учитывая данный подвыбор всей таблицы:

 id   tBegin                orderId   
------------------------------------
 1    2018-10-20 00:00:05   1
 2    2018-10-20 00:05:15   1
 3    2018-10-20 01:00:05   1
 10   2018-10-20 10:03:05   3
 12   2018-10-20 11:04:05   8
 20   2018-10-20 14:15:05   3
 37   2018-10-20 18:12:05   1

Моя цель состоит в том, чтобы сгруппировать данные в следующие

 id   tBegin                orderId   pCount 
--------------------------------------------
 1    2018-10-20 00:00:05   1         3
 10   2018-10-20 10:03:05   3         1
 12   2018-10-20 11:04:05   8         1
 20   2018-10-20 14:15:05   3         1
 37   2018-10-20 18:12:05   1         1

Простой GROUP BY orderID выигранныйничего не получилось, поэтому я подошел со следующими

SELECT 
  MIN(c.id) AS id,
  MIN(c.tBegin) AS tBegin,
  c.orderId,
  COUNT(*) AS pCount
FROM (
    SELECT t2.id, t2.tBegin, t2.orderId,
      ( SELECT TOP 1 t.id
        FROM history t
        WHERE t.tBegin > t2.tBegin
          AND t.orderID <> t2.orderID
          AND <restrict date here further>
        ORDER BY t.tBegin 
       ) AS nextId
    FROM history t2 
) AS c
WHERE <restrict date here>
GROUP BY c.orderID, c.nextId

Я пропустил WHERE s, которые выбирают правильную дату и тестера.Это работает, но швы очень неэффективны.Я работал с небольшими базами данных, но я новичок в SQL Server 2017.

Я очень ценю вашу помощь!

Ответы [ 2 ]

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

Вы можете использовать совокупный подход:

select min(id) as id, max(tBegin), orderid, count(*) 
from (select h.*,
             row_number() over (order by id) as seq1,
             row_number() over (partition by orderid order by id) as seq2
      from history h
     ) h
group by orderid, (seq1 - seq2)
order by id;
0 голосов
/ 19 ноября 2018

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

DECLARE @t TABLE (id INT, tBegin DATETIME, orderId INT);
INSERT INTO @t VALUES
(1 , '2018-10-20 00:00:05', 1),
(2 , '2018-10-20 00:05:15', 1),
(3 , '2018-10-20 01:00:05', 1),
(10, '2018-10-20 10:03:05', 3),
(12, '2018-10-20 11:04:05', 8),
(20, '2018-10-20 14:15:05', 3),
(37, '2018-10-20 18:12:05', 1);

WITH cte1 AS (
    SELECT *, CASE WHEN orderId = LAG(orderId) OVER (ORDER BY tBegin) THEN 0 ELSE 1 END AS chg
    FROM @t
), cte2 AS (
    SELECT *, SUM(chg) OVER(ORDER BY tBegin) AS grp
    FROM cte1
), cte3 AS (
    SELECT *, ROW_NUMBER() OVER (PARTITION BY grp ORDER BY tBegin) AS rn
    FROM cte2
)
SELECT *
FROM cte3
WHERE rn = 1
  • Первый cte назначает «флаг изменения» каждой строке, в которой значение изменилось
  • Второй cte использует промежуточную сумму для преобразования 1 и 0 в число, которое можно использовать для группировки строк
  • Наконец, вы нумеруете строки в каждой группе и выбираете первую строку для каждой группы

Демонстрация по DB Fiddle

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