SQL · funciones de ventana

FIRST_VALUE y LAST_VALUE en SQL

Obtén el valor de la primera o la última fila de una ventana sin agrupar el resultado y aprende por qué el marco de ventana cambia especialmente el comportamiento de LAST_VALUE.

Lectura: 7–9 minSQL comprobadoPráctica con pistas
Contenido de esta guía

Respuesta rápida

FIRST_VALUE(expresión) devuelve el valor de la primera fila del marco de ventana y LAST_VALUE(expresión) el de la última. Ambas funciones se usan con OVER (...) y conservan las filas de detalle.

Patrón seguro para toda la partición
FIRST_VALUE(fecha) OVER (
  PARTITION BY cliente_id
  ORDER BY fecha, id
  ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING
)

LAST_VALUE(fecha) OVER (
  PARTITION BY cliente_id
  ORDER BY fecha, id
  ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING
)

El PARTITION BY define el grupo independiente, ORDER BY decide qué significa «primera» y «última» y el frame determina qué filas están disponibles para la función en cada fila.

Modelo mental: no buscan una fila, leen un valor dentro de la ventana

Estas funciones no eliminan filas ni sustituyen a MIN() o MAX(). La pregunta no es «¿cuál es la fecha menor?», sino «después de ordenar las filas de cada cliente, ¿qué valor tiene la primera o la última fila de ese recorrido?».

Eso permite mostrar, junto a cada pedido, la primera y la última fecha de compra del mismo cliente. El detalle permanece visible porque las funciones de ventana calculan un valor por fila.

Incluye un desempate estable. Si dos filas tienen la misma fecha, añade una clave como id al ORDER BY. Sin un orden total, «primera» o «última» puede no identificar de forma determinista la misma fila.

Ejemplo comprobado: primera y última compra por cliente

Pedidos de dos clientes
SELECT
  id,
  cliente_id,
  fecha,
  FIRST_VALUE(fecha) OVER (
    PARTITION BY cliente_id
    ORDER BY fecha, id
    ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING
  ) AS primera_fecha,
  LAST_VALUE(fecha) OVER (
    PARTITION BY cliente_id
    ORDER BY fecha, id
    ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING
  ) AS ultima_fecha
FROM pedidos
WHERE cliente_id IN (1, 3)
ORDER BY cliente_id, fecha, id;
Resultado comprobado en SQLite 3.46.1
idcliente_idfechaprimera_fechaultima_fecha
10112025-05-022025-05-022025-06-01
10312025-05-102025-05-022025-06-01
11112025-06-012025-05-022025-06-01
10432025-05-112025-05-112025-06-12
10732025-05-202025-05-112025-06-12
11632025-06-122025-05-112025-06-12

Las seis filas siguen en el resultado. Lo que se repite dentro de cada cliente son los valores calculados de la primera y la última fecha.

El detalle que suele romper LAST_VALUE: el marco de ventana

Con un ORDER BY, varios motores usan de forma predeterminada un marco que llega hasta la fila actual o sus pares. En ese caso, LAST_VALUE() puede devolver el valor de la fila actual en vez del último valor de toda la partición.

Suponer que LAST_VALUE siempre mira hasta el final

Ambiguo para la intención «último del cliente»
LAST_VALUE(fecha) OVER (
  PARTITION BY cliente_id
  ORDER BY fecha, id
)

Si necesitas el último valor de toda la partición, declara el marco completo de forma explícita con ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING.

Cuándo usar estas funciones

  • Primera o última fecha: inicio y fin de una secuencia por cliente, empleado o producto.
  • Primer o último estado: cuando el orden temporal define una evolución y quieres conservar cada evento.
  • Valor de referencia: comparar cada fila con el valor inicial o final del mismo grupo.

Si solo necesitas una fila por grupo, una agregación o un patrón Top N por grupo puede ser más directo. Si necesitas mantener todas las filas, las funciones de ventana son la herramienta natural.

Compatibilidad entre motores

PostgreSQL, SQLite, MySQL 8.4 y SQL Server ofrecen FIRST_VALUE y LAST_VALUE. La sintaxis del marco se parece, pero no conviene asumir que las opciones adicionales son idénticas. SQL Server 2022 y posteriores, por ejemplo, documentan IGNORE NULLS y RESPECT NULLS para estas funciones.

La parte más portable de la guía es la idea de PARTITION BY + ORDER BY + un frame explícito. Si necesitas ignorar NULL o una variante avanzada, confirma primero la versión y el motor.

Práctica: conserva cada pedido y muestra el total inicial y final

Intermedia · ventanas

Compara cada pedido con los extremos del cliente

Para los clientes 1 y 3, devuelve id, cliente_id, fecha, total, el total del primer pedido y el total del último pedido. Ordena cronológicamente y usa id como desempate.

Qué debes recordar

  • FIRST_VALUE y LAST_VALUE leen extremos definidos por el orden de una ventana.
  • Conservan las filas de detalle.
  • LAST_VALUE depende especialmente del frame; declara el marco completo cuando buscas el último valor de toda la partición.
  • Añade un desempate estable al ORDER BY.

Conceptos relacionados

Fuentes técnicas consultadas

Las referencias oficiales se usaron para verificar semántica, marcos y compatibilidad.