PostgreSQL
 sql >> Base de Dados >  >> RDS >> PostgreSQL

Função condicional de lead/lag PostgreSQL?


Sua definição:

a atividade do grupo B sempre ocorre após a atividade do grupo A.

.. implica logicamente que há, por usuário, 0 ou 1 atividade B após 1 ou mais atividades A. Nunca mais de 1 B atividades em sequência.

Você pode fazê-lo funcionar com uma única função de janela, DISTINCT ON e CASE , que deve ser o caminho mais rápido para poucos linhas por usuário (veja também abaixo):
SELECT name
     , CASE WHEN a2 LIKE 'B%' THEN a1 ELSE a2 END AS activity
     , CASE WHEN a2 LIKE 'B%' THEN a2 END AS next_activity
FROM  (
   SELECT DISTINCT ON (name)
          name
        , lead(activity) OVER (PARTITION BY name ORDER BY time DESC) AS a1
        , activity AS a2
   FROM   t
   WHERE (activity LIKE 'A%' OR activity LIKE 'B%')
   ORDER  BY name, time DESC
   ) sub;

db<>mexa aqui

Um SQL CASE expressão padrão para NULL se não houver ELSE branch é adicionado, então eu mantive isso curto.

Assumindo time está definido NOT NULL . Caso contrário, você pode querer adicionar NULLS LAST . Por quê?
  • Classificar por coluna ASC, mas primeiro com valores NULL?

(activity LIKE 'A%' OR activity LIKE 'B%') é mais detalhado que activity ~ '^[AB]' , mas normalmente mais rápido em versões mais antigas do Postgres. Sobre a correspondência de padrões:
  • Correspondência de padrões com LIKE, SIMILAR TO ou expressões regulares no PostgreSQL

Funções de janela condicional?


Isso é realmente possível . Você pode combinar o agregado FILTER cláusula com o OVER cláusula de funções de janela. No entanto :

  1. O FILTER A cláusula em si só pode funcionar com valores da linha atual.

  2. Mais importante, FILTER não é implementado para funções genuínas puras como lead() ou lag() (até Postgres 13) - apenas para funções agregadas.

Se você tentar:
lead(activity) FILTER (WHERE activity LIKE 'A%') OVER () AS activity

O Postgres lhe dirá:
FILTER is not implemented for non-aggregate window functions

Sobre FILTER :
  • Colunas agregadas com filtros adicionais (distintos)
  • Referenciando a linha atual na cláusula FILTER da função de janela

Desempenho


Para poucos usuários com poucos linhas por usuário, praticamente qualquer a consulta é rápida, mesmo sem index.

Para muitos usuários e poucos linhas por usuário, a primeira consulta acima deve ser mais rápida. Ver:
  • Selecionar a primeira linha em cada grupo GROUP BY?

Para muitos linhas por usuário, há (potencialmente muito ) técnicas mais rápidas, dependendo dos detalhes de sua configuração. Ver:
  • Otimize a consulta GROUP BY para recuperar a última linha por usuário