Sou um usuário iniciante de SQL e estou com dificuldades em uma sqlite
consulta sobre um arquivo GROUP BY
. Aqui está um exemplo simplificado do meu problema usando os dados desta tabela:
id, pid, tid, duration
1, 1, 12, 0.099999
2, 1, 13, 0.105
3, 1, 14, 0.102
4, 1, 15, 0.1
5, 1, 22, 0.12
6, 1, 23, 0.101
7, 1, 24, 0.11
8, 2, 13, 0.105
9, 2, 14, 0.102
10, 2, 15, 0.1
11, 2, 16, 0.11
12, 2, 17, 0.11
13, 2, 18, 0.0995
14, 2, 19, 0.0998
15, 1, 12, 0.099999
16, 1, 13, 0.105
17, 1, 23, 0.101
18, 1, 24, 0.11
19, 2, 15, 0.1
20, 2, 16, 0.11
21, 2, 17, 0.11
22, 2, 18, 0.0995
23, 2, 19, 0.0998
24, 1, 13, 0.105
25, 1, 15, 0.1
26, 1, 22, 0.12
27, 1, 23, 0.101
28, 1, 24, 0.11
29, 2, 13, 0.105
30, 2, 14, 0.102
31, 2, 15, 0.1
32, 2, 16, 0.11
33, 2, 19, 0.0998
Estou tentando contar o número de tid
s únicos para cada um pid
e somar o duration
for each pid
. Embora tid
seja único, seu correspondente duration
não é único. Observação: no caso real, duration
é na verdade uma coluna unida tid
e estou mostrando apenas as colunas nas quais estou tentando operar aqui.
Também quero descobrir o número de "visitas" - se houver uma interrupção no "unique_timesteps" de mais de 5 tid
s, isso conta como uma visita separada - então, neste exemplo, pid=1
teríamos 2 visitas, enquanto pid=2
teríamos uma visita.
Aqui está o que espero que seja o resultado final:
┌───────┬───────────┬────────────────────┬────────┐
│ pid │ num_times │ exposure_time │ visits │
│ int64 │ int64 │ double │ int64 │
├───────┼───────────┼────────────────────┼──────-─┤
│ 1 │ 7 │ 0.7379990000000001 │ 2 │
│ 2 │ 7 │ 0.7263000000000001 │ 1 │
└───────┴───────────┴────────────────────┴────────┘
Executo a seguinte consulta nos dados, mas ela não retorna os resultados esperados para o agrupamento.
SELECT
pid,
COUNT(DISTINCT(tid)) AS num_times,
SUM(DISTINCT(duration)) AS exposure_time,
GROUP_CONCAT(DISTINCT(id)) AS rows,
GROUP_CONCAT(DISTINCT(tid)) AS unique_timesteps
FROM
distinct_example
GROUP BY
pid
ORDER BY
pid;
Aqui está o resultado onde estou adicionando as duas últimas colunas para contexto:
┌───────┬───────────┬────────────────────┬──────────────────────────────────────────────────┬──────────────────────┐
│ pid │ num_times │ exposure_time │ rows │ unique_timesteps │
│ int64 │ int64 │ double │ varchar │ varchar │
├───────┼───────────┼────────────────────┼──────────────────────────────────────────────────┼──────────────────────┤
│ 1 │ 7 │ 0.7379990000000001 │ 24,4,2,7,25,27,16,1,15,18,3,5,28,6,17,26 │ 12,23,15,22,24,13,14 │
│ 2 │ 7 │ 0.6163 │ 13,14,32,9,8,19,23,33,12,31,30,20,22,11,10,21,29 │ 16,19,17,13,14,18,15 │
└───────┴───────────┴────────────────────┴──────────────────────────────────────────────────┴──────────────────────┘
Em cada caso, há 7 intervalos de tempo exclusivos registrados para cada um pid
, conforme mostrado corretamente na segunda coluna. A terceira coluna deve ser a soma da duration
coluna para a respectiva group by
operação em pid
. Isso deve resultar em (0,737999, 0,726300) como resultado para , exposure_time
pois duration
deve ser somado em , unique_timesteps
em vez de durations
. No entanto, entendi mal o uso de DISTINCT
dentro de , GROUP BY
e uma das durações de pid=2
foi negligenciada (0,11).
Acho que devo fazer alguma subconsulta para selecionar as linhas corretas para usar como índice, mas não consigo entender como fazer isso.
Não tenho ideia de como calcular o visits
resultado, mas presumo que isso poderia ser feito com algumas subconsultas e uma função de janela?
Usar um CTE que agrupa por pid,tid primeiro ajudará a produzir os resultados esperados
violino
exposure_time
: garantindo a exclusividadeComo você analisou corretamente, seu
DISTINCT duration
retorna apenas uma ocorrência quando doistid
compartilham o mesmoduration
. O que naturalmente corresponde à sua necessidade seria o do PostgreSQLDISTINCT ON
, que não existe no SQLite, então você terá que emulá-lo.Poderíamos usar subseleções com
LIMIT 1
(para obter 1 valor para cada tid selecionado),mas prefiro usar Expressões de Tabela Comuns que podem ser vistas como criação sequencial de tabelas temporárias intermediárias, ajudando a manter a organização (você constrói sua consulta progressivamente, tabela intermediária por tabela intermediária) e facilitando o diagnóstico (você pode,
select *
a partir de qualquer tabela intermediária, verificar se a etapa do processo está correta em relação às suas expectativas).Então, primeiro renormalizaremos todos os seus dados em CTEs , garantindo que eles contenham apenas valores únicos (claro, se você ainda tiver sua tabela
tid
/ original, sinta-se à vontade para começar a partir dela) e, em seguida, somaremos as tabelas sem (porque temos certeza de que temos apenas uma linha por entrada / e por casal / ):duration
DISTINCT
tid
duration
tid
pid
visits
: função de janela para contar a distância entre as mesmas entradas pidPara o seu caso
visits
, você está certo, uma função de janela será a maneira mais fácil (também poderíamos unir a tabela a si mesmaON b.id BETWEEN a.id - 6 and a.id - 1 WHERE b.pid = a.pid
para encontrar predecessores próximos). Não podemoscomparar linhas anteriores com a linha atual usando uma função de janela ( ), então particionaremos por pid e usaremos a ordem deles dentro do conjunto de dados completo, que eu entendo ser , para ver a que distância cada entrada está.
MIN(CASE WHEN pid = CURRENT.pid THEN 0 ELSE 1 END) OVER (ORDER BY id ROWS BETWEEN 5 PRECEDING AND 1 PRECEDING) AS INCREASE
id
Contudo
Agora podemos juntar as nossas duas mesas (cada uma delas garantindo uma entrada por
pid
):Provavelmente poderíamos ter compactado (agrupando algumas consultas), mas ajudar esses dois problemas distintos a permanecerem distintos na consulta final facilitará a manutenção.
Tudo funciona nesse violino .