Eu tenho uma tabela com números como este (o status é GRATUITO ou ATRIBUÍDO)
id_set number status ----------------------- 1 000001 ATRIBUÍDO 1 000002 GRÁTIS 1 000003 ATRIBUÍDO 1 000004 GRÁTIS 1 000005 GRÁTIS 1 000006 ATRIBUÍDO 1 000007 ATRIBUÍDO 1 000008 GRÁTIS 1 000009 GRÁTIS 1 000010 GRÁTIS 1 000011 ATRIBUÍDO 1 000012 ATRIBUÍDO 1 000013 ATRIBUÍDO 1 000014 GRÁTIS 1 000015 ATRIBUÍDO
e eu preciso encontrar "n" números consecutivos, então para n = 3, a consulta retornaria
1 000008 GRÁTIS 1 000009 GRÁTIS 1 000010 GRÁTIS
Ele deve retornar apenas o primeiro grupo possível de cada id_set (na verdade, seria executado apenas para id_set por consulta)
Eu estava checando as funções do WINDOW, tentei algumas consultas COUNT(id_number) OVER (PARTITION BY id_set ROWS UNBOUNDED PRECEDING)
, mas foi tudo o que consegui :) Não consegui pensar em lógica, como fazer isso no Postgres.
Eu estava pensando em criar uma coluna virtual usando as funções do WINDOW, contando as linhas anteriores para cada número em que status = 'FREE' e, em seguida, selecione o primeiro número, em que a contagem é igual ao meu número "n".
Ou talvez agrupe números por status, mas apenas de um ASSIGNED para outro ASSIGNED e selecione apenas grupos que contenham pelo menos "n" números
EDITAR
Encontrei esta consulta (e a alterei um pouco)
WITH q AS
(
SELECT *,
ROW_NUMBER() OVER (PARTITION BY id_set, status ORDER BY number) AS rnd,
ROW_NUMBER() OVER (PARTITION BY id_set ORDER BY number) AS rn
FROM numbers
)
SELECT id_set,
MIN(number) AS first_number,
MAX(number) AS last_number,
status,
COUNT(number) AS numbers_count
FROM q
GROUP BY id_set,
rnd - rn,
status
ORDER BY
first_number
que produz grupos de números GRATUITOS / ATRIBUÍDOS, mas eu gostaria de ter todos os números do primeiro grupo que atenda à condição
id_set
ou apenas um? Atualize sua pergunta se isso foi feito como parte desde o início. (Para que outras pessoas possam ver todos os requisitos e oferecer suas sugestões ou atualizar suas respostas.)Uma variante simples e rápida :
Requer uma sequência contínua de números em
number
(conforme fornecido na pergunta).Funciona para qualquer número de valores possíveis em
status
além disso'FREE'
, mesmo comNULL
.A principal característica é subtrair
row_number()
a partir denumber
depois de eliminar linhas não-qualificadas. Os números consecutivos terminam na mesmagrp
- egrp
também é garantido que esteja em ordem crescente .Então você pode
GROUP BY grp
e contar os membros. Como você parece querer a primeira ocorrênciaORDER BY grp LIMIT 1
e obtém a posição inicial e o comprimento da sequência (pode ser> = n ).Conjunto de linhas
Para obter um conjunto real de números, não procure a tabela outra vez. Muito mais barato com
generate_series()
:Se você realmente deseja uma string com zeros à esquerda, como os valores de exemplo, use
to_char()
com oFM
modificador (modo de preenchimento):SQL Fiddle com caso de teste estendido e ambas as consultas.
Resposta intimamente relacionada:
fonte
Essa é uma maneira bastante genérica de fazer isso.
Lembre-se de que depende da sua
number
coluna ser consecutiva. Se não for uma função do Windows e / ou uma solução do tipo CTE provavelmente será necessária:fonte
M.number-consec+1
(por exemplo, para 10, seria necessário10-3+1=8
).number
campo. Boa chamada na matemática, eu vou corrigi-la.EXISTS
poderia ser simplificado. Uma vez que só precisa ter certeza de qualquer n existem linhas anteriores, podemos largar oAND status = 'FREE'
. E eu gostaria de mudar a condição na 2ªEXISTS
parastatus <> 'FREE'
a endurecer-lo contra opções adicionadas no futuro.Isso retornará apenas o primeiro dos três números. Não requer que os valores de
number
sejam consecutivos. Testado no SQL-Fiddle :E isso mostrará todos os números (onde existem 3 ou mais
'FREE'
posições consecutivas ):fonte
Nesse caso, 5 números consecutivos - portanto, a diferença deve ser 4 ou, em outras palavras,
count(r3.number) = n
er2.number = r1.number + n - 1
.Com junções:
fonte
JOIN
sintaxe moderna ?fonte
{ }
botão no editor. Desfrutar!