sql >> Base de Datos >  >> RDS >> PostgreSQL

¿Función condicional de adelanto/retraso PostgreSQL?

Tu definición:

la actividad del grupo B siempre tiene lugar después de la actividad del grupo A.

.. lógicamente implica que hay, por usuario, 0 o 1 actividad B después de 1 o más actividades A. Nunca más de 1 B actividades en secuencia.

Puede hacer que funcione con una función de ventana única, DISTINCT ON y CASE , que debería ser la forma más rápida para pocos filas por usuario (ver también a continuación):

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<>violín aquí

Un CASE de SQL expresión por defecto es NULL si no ELSE se agrega la rama, así que lo mantuve breve.

Asumiendo time se define NOT NULL . De lo contrario, es posible que desee agregar NULLS LAST . ¿Por qué?

  • ¿Ordenar por columna ASC, pero los valores NULL primero?

(activity LIKE 'A%' OR activity LIKE 'B%') es más detallado que activity ~ '^[AB]' , pero generalmente más rápido en versiones anteriores de Postgres. Acerca de la coincidencia de patrones:

  • Coincidencia de patrones con LIKE, SIMILAR TO o expresiones regulares en PostgreSQL

¿Funciones de ventana condicionales?

Eso es realmente posible . Puede combinar el agregado FILTER cláusula con OVER cláusula de funciones de ventana. Sin embargo :

  1. El FILTER la cláusula en sí solo puede funcionar con valores de la fila actual.

  2. Más importante aún, FILTER no está implementado para funciones genuinas puras como lead() o lag() (hasta Postgres 13) - solo para funciones agregadas.

Si intentas:

lead(activity) FILTER (WHERE activity LIKE 'A%') OVER () AS activity

Postgres le dirá:

FILTER is not implemented for non-aggregate window functions

Acerca de FILTER :

  • Columnas agregadas con filtros adicionales (distintos)
  • Hacer referencia a la fila actual en la cláusula FILTER de la función de ventana

Rendimiento

Para pocos usuarios con pocos filas por usuario, prácticamente cualquiera la consulta es rápida, incluso sin índice.

Para muchos usuarios y pocos filas por usuario, la primera consulta anterior debería ser la más rápida. Ver:

  • ¿Seleccionar la primera fila en cada grupo GROUP BY?

Para muchos filas por usuario, hay (potencialmente mucho ) técnicas más rápidas, dependiendo de los detalles de su configuración. Ver:

  • Optimizar la consulta GROUP BY para recuperar la fila más reciente por usuario