Estou tentando contar o número de itens se eles não estiverem dentro de 30 segundos do primeiro item em um "grupo". Estou tendo dificuldade em descobrir isso.
Então, eu tenho essa tabela:
WITH ADates AS (
SELECT
Id
, SharedId
, TheDateTime
FROM (VALUES
(CAST(1 AS int), CAST(1 AS int), CAST('2019-01-01 01:01:00.00' AS datetime2(7))),
(2, 1, '2019-01-01 01:01:33.00'),
(3, 1, '2019-01-01 01:02:00.00'),
(4, 1, '2019-01-01 01:02:01.00'),
(5, 1, '2019-01-01 01:02:04.00'),
(6, 1, '2019-01-01 01:06:15.00'),
(7, 2, '2019-01-01 01:06:00.00'),
(8, 2, '2019-01-01 01:06:45.00'),
(9, 1, '2019-01-01 01:02:31.00'),
(10, 2, '2019-01-01 01:06:05.00'),
(11, 2, '2019-01-01 01:06:46.00'),
) X (Id, SharedId, TheDateTime)
)
Então, o resultado esperado que estou procurando é:
+==========+=======+
| SharedId | Count |
+==========+=======+
| 1 | 4 |
+----------+-------+
| 2 | 2 |
+----------+-------+
Os números são determinados por:
- Conte desde o primeiro no novo grupo.
- Não dentro de 30 segundos do grupo anterior, então é um novo grupo e conta.
- Não conte, pois está a 30 segundos de 2.
- Não conte, pois está a 30 segundos de 2.
- Contar desde que não esteja dentro de 30 segundos do grupo anterior (Item 2).
- Contar desde que não esteja dentro de 30 segundos do grupo anterior (item 2).
- Contagem em novo grupo para SharedId.
- Contar desde que não esteja dentro do agrupamento anterior.
Eu estou pensando que eu deveria estar fazendo um Window Function
para isso. Só não tenho certeza de como fazer isso depender apenas do primeiro do grupo.
Tem algo a ver com o item 6 estar depois do item 7 que está em outro grupo. Por isso, é visto como uma nova contagem na minha consulta, resultando em 5. Este tempo com id=6 está correto? pode ser depois de id=7?
A consulta ficou tão complexa que não consigo explicar, ou já é tarde demais (?), o que não é bom, mas…. ?
O próximo parece produzir os resultados corretos (com os 9 registros):
Categorização do problema
Eu estava procurando uma maneira de usar uma função analítica que acompanhe as manipulações em linha. Uma função analítica de execução única só é capaz de realizar tanto, mas não a ponto de resolver esse problema. O problema com o aninhamento de funções analíticas é que perdemos informações sobre nosso padrão dinâmico.
Para permitir a correspondência dinâmica de padrões embutidos, no Oracle você pode usar MATCH_RECOGNIZE . Eu não tinha ideia de como fazer isso no Sql Server . Então me deparei com um problema semelhante, que foi resolvido usando um CTE recursivo .
Solução proposta
CteBase
eCteRecursive
são fortemente inspirados pela resposta de Bogdan Sahlean nesta questão relacionada .A respeito: