Ante una consulta en el foro me pareció interesante mostrar aquí en el blog como podemos obtener las primeras o las últimas Facturas vendidas a un Cliente. Por supuesto que no es el único caso, hay miles de casos similares, que pueden involucrar a productos, proveedores, vendedores, cobradores, o lo que sea. Lo importante es conocer la técnica para poder responder a esta clase de preguntas.

Veamos el problema:

En nuestra tabla cabecera de ventas (llamada VENTASCAB) guardamos el Identificador del Cliente, el Número de la Factura de venta y otros datos más. Quisiéramos obtener:

  1. Las 3 primeras Facturas vendidas a cada Cliente
  2. Las 3 últimas Facturas vendidas a cada Cliente

FACTURAS01

Captura 1. Si haces clic en la imagen la verás más grande

En la Captura 1. vemos algunos identificadores y algunos números de Factura, para que se entienda el ejemplo.

Caso 1. Obteniendo las 3 primeras Facturas vendidas a cada Cliente

Listado 1.

SELECT
   A.VTC_IDECLI,
   A.VTC_NRODOC
FROM
   VENTASCAB A
WHERE
   A.VTC_NRODOC IN (SELECT 
                       FIRST 3 
                       B.VTC_NRODOC 
                    FROM 
                       VENTASCAB B 
                    WHERE 
                       A.VTC_IDECLI = B.VTC_IDECLI
                    ORDER BY
                       B.VTC_IDECLI,
                       B.VTC_NRODOC
                   )
ORDER BY
   A.VTC_IDECLI,
   A.VTC_NRODOC

FACTURAS02

Captura 2. Si haces clic en la imagen la verás más grande

Caso 2. Obteniendo las 3 últimas Facturas vendidas a cada Cliente

Listado 2.

SELECT
   A.VTC_IDECLI,
   A.VTC_NRODOC
FROM
   VENTASCAB A
WHERE
   A.VTC_NRODOC IN (SELECT 
                       FIRST 3 
                       B.VTC_NRODOC 
                    FROM 
                       VENTASCAB B 
                    WHERE 
                       A.VTC_IDECLI = B.VTC_IDECLI
                    ORDER BY
                       B.VTC_IDECLI DESCENDING,
                       B.VTC_NRODOC DESCENDING
                   )
ORDER BY
   A.VTC_IDECLI,
   A.VTC_NRODOC

FACTURAS03

Captura 3. Si haces clic en la imagen la verás más grande

Explicación:

Cuando en la cláusula WHERE usamos el predicado IN lo que hacemos es un filtrado múltiple, o sea cuando varias filas pueden cumplir la condición de filtro. Aquí lo que necesitamos son 3 filas por cada cliente, entonces mediante una subconsulta obtenemos esas 3 filas. Como la subconsulta está ordenada por Identificador del Cliente y Número de la Factura entonces en el Caso 1. obtenemos las primeras 3 Facturas de cada cliente. Para obtener las 3 últimas Facturas del cliente ordenamos a la subconsulta de mayor a menor, o sea de forma descendente, como vemos en el Caso 2.

Fíjate que la palabra DESCENDING debe colocarse a continuación de cada columna, porque si no se coloca a continuación de una columna entonces esa columna estará ordenada de forma ascendente, que es lo normal, pero no es lo que necesitamos. Aquí necesitamos que ambas columnas se ordenen de forma descendente.

Importantísimo: Debemos tener un índice ascendente compuesto por las columnas VTC_IDECLI y VTC_NRODOC y otro índice descendente también compuesto por las columnas VTC_IDECLI y VTC_NRODOC. ¿Por qué? porque si no tenemos esos índices entonces el Firebird se verá obligado a ordenar la tabla y eso en tablas grandes puede demorarse una eternidad. Así que, si escribes una consulta similar a la del Caso 1. o a la del Caso 2. y los minutos pasan y pasan y no obtienes el resultado de la consulta, es seguro que te falta crear uno de los índices o ambos.

Conclusión:

Cuando queremos filtrar una tabla para ver solamente algunas de las filas, una de las técnicas es usar el predicado IN en la cláusula WHERE.

El predicado IN es una forma abreviada de escribir el operador de comparación OR y es muy útil para escribir menos y entender mejor.

Si no tenemos índices, consultas como las del Caso 1. y del Caso 2. pueden demorarse muchísimo, así que debemos crear esos índices para obtener una buena velocidad de respuesta.

Artículos relacionados:

El índice del blog Firebird21

El foro del blog Firebird21

Anuncios