Estou usando o PostgreSQL 12.0 e tentando obter a sequência mais longa de linhas contínuas para uma coluna e valor específicos.
A tabela é chamada team2 e contém os resultados de uma equipe que se parece com:
match_id (pk), team_name (varchar), opposition (varchar), match_result (varchar)
Minha consulta está tentando encontrar a sequência mais longa de 'Win' em match_result. Há 23 vitórias no total e usando o olho a sequência mais longa deve retornar 5. No entanto, 23 são retornados. Como posso alterar minha consulta para selecionar apenas a sequência mais longa?
WITH ConsecutiveSequences AS (
SELECT
match_result,
ROW_NUMBER() OVER () - ROW_NUMBER() OVER (ORDER BY match_id) AS grp
FROM team2
WHERE match_result = 'Win'
),
GroupedSequences AS (
SELECT
match_result,
COUNT(*) AS consecutive_count
FROM ConsecutiveSequences
GROUP BY match_result, grp
)
SELECT
COALESCE(MAX(consecutive_count), 0) AS longest_consecutive_sequence
FROM GroupedSequences;
"Sequência mais longa de linhas contínuas" implica uma ordem, que neste caso é match_id.
Vamos fazer um exemplo genérico:
Então, vamos obter o comprimento da sequência mais longa de linhas contíguas, na ordem match_id, tendo o mesmo resultado e crítico. Detectar uma sequência sólida de valores idênticos significa comparar cada linha com a anterior, o que significa que a função de janela LAG() é necessária.
Não podemos usar match_result em WHERE como você fez na sua pergunta, porque isso eliminaria as linhas com valores errados... e precisamos manter essas linhas, pois elas atuam como um delimitador entre execuções de valores de resultados idênticos. Na sua consulta, você mantém apenas as vitórias, portanto não há partidas perdidas para definir os limites em torno de uma sequência de vitórias. Resta apenas uma única sequência de vitórias. Assim você obtém a contagem de vitórias na tabela, como percebeu, o que não é o que você deseja.
Portanto, precisamos localizar o início e o fim de uma sequência de linhas com o mesmo crítico e resultado, comparando as linhas atuais e anteriores. Uma coisa importante a lembrar é que LAG() retorna NULL para a primeira linha da partição, portanto é necessário que haja um caso especial para a primeira linha.
Então agora temos new_run=true no início de uma nova sequência. Para contar as linhas em uma sequência, precisamos dar a cada sequência um id e usar count() e agrupar por, ou obter row_number() para a primeira e última linha da sequência e subtraí-las.
Para detectar a última linha de uma sequência, precisamos comparar a linha atual com a próxima, usando lead() em vez de lag(). No entanto, lead() será NULL se esta for a última linha da partição. No caso anterior detectamos a primeira linha na partição com row_number()=1 mas isso não é possível para a última linha porque seu row_number() não é conhecido. Portanto, usaremos lead() em uma coluna não anulável como match_id. "resultado" também pode não ser usado se não for anulável.
Depois de verificar se os resultados estão corretos (especialmente nos limites), podemos remover as linhas com start_run e end_run definidos como NULL e manter apenas as linhas que indicam o início e o fim de uma execução, e então obter seu comprimento. O bit com COALESCE é devido a execuções com thatt_run na mesma linha ou na linha anterior se o comprimento for 1 ou maior.
Para obter a execução mais longa, você pode substituir a primeira e a última linhas da consulta anterior por