Eu tenho cerca de um bilhão de linhas de dados em uma tabela com um nome e um número inteiro no intervalo de 1 a 288. Para um determinado nome , todo int é único e nem todo número possível do intervalo está presente - portanto, existem lacunas.
Esta consulta gera um exemplo de caso:
--what I have:
SELECT *
FROM ( VALUES ('foo', 2),
('foo', 3),
('foo', 4),
('foo', 10),
('foo', 11),
('foo', 13),
('bar', 1),
('bar', 2),
('bar', 3)
) AS baz ("name", "int")
Gostaria de gerar uma tabela de pesquisa com uma linha para cada nome e sequência de números inteiros contíguos. Cada linha conteria:
name - o valor do início da coluna de nome - o primeiro número inteiro no final da sequência contígua - o valor final no período de sequência contígua - end - start + 1
Esta consulta gera saída de exemplo para o exemplo acima:
--what I need:
SELECT *
FROM ( VALUES ('foo', 2, 4, 3),
('foo', 10, 11, 2),
('foo', 13, 13, 1),
('bar', 1, 3, 3)
) AS contiguous_ranges ("name", "start", "end", span)
Como tenho muitas linhas, mais eficiente é melhor. Dito isto, só preciso executar esta consulta uma vez, portanto não é um requisito absoluto.
Desde já, obrigado!
Editar:
Devo acrescentar que as soluções PL / pgSQL são bem-vindas (por favor, explique quaisquer truques extravagantes - ainda sou novo no PL / pgSQL).
fonte
Respostas:
Que tal usar
with recursive
vista de teste:
inquerir:
resultado:
Eu ficaria interessado em saber como isso funciona na sua tabela de bilhões de linhas.
fonte
Você pode fazer isso com funções de janelas. A idéia básica é usar as funções de janelas
lead
elag
janelas para puxar as linhas à frente e atrás da linha atual. Então, podemos calcular se temos o início ou o fim da sequência:(Usei uma visualização para facilitar a lógica abaixo). Agora sabemos se a linha é um começo ou um fim. Temos que recolher isso em linha:
Parece correto para mim :)
fonte
Outra solução de função de janela. Nenhuma idéia sobre eficiência, adicionei o plano de execução no final (embora com tão poucas linhas, provavelmente não tenha muito valor). Se você quiser brincar: Teste do SQL-Fiddle
Tabela e dados:
Inquerir:
Plano de consulta
fonte
No SQL Server, eu adicionaria mais uma coluna chamada previousInt:
Eu usaria uma restrição CHECK para garantir que previousInt <int e uma restrição FK (name, previousInt) se refiram a (name, intIn) e mais algumas restrições para garantir a integridade dos dados à prova d'água. Feito isso, selecionar lacunas é trivial:
Para acelerar, posso criar um índice filtrado que inclua apenas lacunas. Isso significa que todas as suas lacunas são pré-computadas, portanto, as seleções são muito rápidas e as restrições garantem a integridade de seus dados pré-computados. Estou usando bastante essas soluções, elas estão por todo o meu sistema.
fonte
Você pode procurar pelo método Tabibitosan:
Basicamente:
Eu acho esse desempenho melhor:
fonte
um plano aproximado:
Repita de 2. até que não ocorra mais atualização. A partir daí, torna-se complicado, górdio, com o agrupamento de no máximo minutos e minutos máx. Eu acho que eu iria para uma linguagem de programação.
PS: Uma boa tabela de amostra com alguns valores de amostra seria boa, e poderia ser usada por todos, para que nem todos criem seus dados de teste do zero.
fonte
Esta solução é inspirada na resposta de nate c usando funções de janelas e a cláusula OVER. Curiosamente, essa resposta é revertida para subconsultas com referências externas. É possível concluir a consolidação da linha usando outro nível de funções de janelas. Pode não parecer muito bonito, mas presumo que seja mais eficiente, pois utiliza a lógica interna das poderosas funções de janelas.
Percebi pela solução da nate que o conjunto inicial de linhas já produzia os sinalizadores necessários para 1) selecionar os valores de intervalo inicial e final AND 2) para eliminar as linhas extras no meio. A consulta aninhou subconsultas com duas profundidades apenas devido a limitações das funções de janela, que restringem como os aliases da coluna podem ser usados. Logicamente, eu poderia ter produzido os resultados com apenas uma subconsulta aninhada.
Algumas outras notas : O código a seguir é para SQLite3. O dialeto SQLite é derivado do postgresql, portanto é muito semelhante e pode até funcionar inalterado. Adicionei restrição de enquadramento às cláusulas OVER, pois as funções
lag()
elead()
precisam apenas de uma janela de linha única, antes e depois respectivamente (portanto, não havia necessidade de manter o conjunto padrão de todas as linhas anteriores). Também optei pelos nomesfirst
e,last
como a palavraend
é reservada.Os resultados são exatamente como as outras respostas, como se espera:
fonte