De DBF a SQL (18). Paginación

Hay ocasiones en las cuales se requiere obtener de las tablas una cantidad fija de filas, el caso más común es para mostrar esas filas en una grilla. Si por ejemplo una tabla tiene 450.000 filas, escribir un SELECT que te traiga esas 450.000 filas sería un gran error, y por varios motivos:

  1. Ningún usuario mirará tantas filas
  2. Habrá muchísimo tráfico en la red, innecesariamente. Eso la volverá lenta
  3. Si varios usuarios están ejecutando ese SELECT, puedes llegar a saturar la red
  4. El usuario tardará mucho en obtener las filas que quiere ver

Para solucionar esos problemas es usual utilizar una técnica llamada paginación.

Por ejemplo, en la grilla muestras las primeras 100 filas, si el usuario quiere ver las siguientes 100 filas, entonces debe hacer clic en un botón. Cada vez que hace clic en ese botón se le muestran 100 filas más.

¿Cuáles son las ventajas de la paginación?

  1. La cantidad de filas que se obtienen del SELECT es relativamente pequeña (en nuestro ejemplo, serían 100 filas)
  2. La velocidad es muy alta (no es lo mismo obtener 100 filas que obtener 450.000 filas)
  3. No perjudicas a los demás usuarios

Casi todos los motores SQL ofrecen una forma sencilla de hacer paginación. Por ejemplo, en Firebird se escribiría:

Listado 1. Haciendo paginación en Firebird. Obteniendo las primeras 100 filas

SELECT
   *
FROM
   MiTabla
ROWS
   1 TO 100

Listado 2. Haciendo paginación en Firebird. Obteniendo las siguientes 100 filas

SELECT
   *
FROM
   MiTabla
ROWS
   101 TO 200

En el Listado 1. y en el Listado 2. vemos como se pueden obtener la cantidad de filas que se desean cuando usamos Firebird. Es muy fácil.

Lamentablemente, el comando SELECT del Visual FoxPro no cuenta con esta posibilidad. Sin embargo podemos hacer paginación usando un truco. Y para ello haremos uso de una subconsulta.

La tabla de CLIENTES

Captura 1. Las filas de la tabla CLIENTES

Haciendo paginación con Visual FoxPro

Como nativamente el Visual FoxPro no nos permite hacer paginación, crearemos un procedimiento que se encargará de esa tarea.

Este PROCEDURE (salvo algunas pequeñas modificaciones estéticas realizadas por el autor de este blog) ha sido compartido por Víctor Hugo Espínola de Paraguay, en el grupo RinconFox del Whatsapp. Muchas gracias Víctor Hugo, muy buen aporte.

Listado 3. Un PROCEDURE para poder hacer paginación

PROCEDURE PAGINA_SELECT
LPARAMETERS tcTabla, tcIdentificador, tcOrdenarPor, tnTamanoPagina, tnPaginaNro
LOCAL lnFilasExcluidas, lcCondicionWhere, lcConsulta, llConsultaOK

   *--- tcTabla        : La tabla que contiene los datos
   *--- tcIdentificador: La Primary Key o Unique Key de la tabla
   *--- tcOrdenarPor   : La columna (o columnas) por las cuales se desea ordenar a la tabla
   *--- tnTamanoPagina : El tamaño de cada página, o sea, la cantidad de filas por página
   *--- tnPaginaNro    : El número de la página que se desea extraer

   tnTamanoPagina = Max(tnTamanoPagina, 1) && Para asegurar que la Página tenga al menos una fila
   tnPaginaNro    = Max(tnPaginaNro, 1)    && Para asegurar que el Número de la Página sea al menos 1

   *--- lnFilasExcluidas: La cantidad de filas que estarán excluidas
   *--- lcCondicionWhere: La condición para mostrar o no la primera página

   lnFilasExcluidas = (tnPaginaNro - 1) * tnTamanoPagina
   lcCondicionWhere = Iif(lnFilasExcluidas = 0, "WHERE 1=0", "")

   TEXT TO M.lcConsulta NOSHOW TEXTMERGE PRETEXT 15
      SELECT
         TOP <>
         *
      FROM
         <>
      WHERE
         <> NOT IN (SELECT
                                          TOP <>
                                          <>
                                       FROM
                                          <>
                                          <>
                                       ORDER BY
                                          <>)
      ORDER BY
         <>
   ENDTEXT

   =MessageBox(M.lcConsulta)

   =ExecScript(M.lcConsulta)

ENDPROC
*
*

Ejemplos de uso

Para hacerlo sencillo, en los siguientes ejemplos cada página tendrá 3 filas. Eso significa que en la primera página estarán las filas del 1 al 3, en la segunda página las filas del 4 al 6, en la tercera página las filas del 7 al 9, etcétera.

Ejemplo 1. Para ver la primera página

DO PAGINA_SELECT WITH «CLIENTES», «CLI_IDENTI», «CLI_NOMBRE», 3, 1

Captura 2. La consulta que ejecutará el Visual FoxPro

La condición de la subconsulta siempre dará falso como resultado, porque 1 siempre será diferente que 0. Eso significa que ninguna fila se obtendrá de la subconsulta, porque siempre estará totalmente vacía. Por lo tanto, la columna CLI_IDENTI nunca se encontrará en esa subconsulta y en consecuencia se mostrarán las 3 primeras filas de la tabla CLIENTES.

¿Entiendes la lógica empleada allí?

NOTA: En lugar de escribir 1 = 0 también se podría haber escrito .F., pero hay una diferencia y es que 1 = 0 funcionará en cualquier motor SQL cuando queremos establecer una condición como falsa, en cambio .F. solamente funcionará en Visual FoxPro.

Captura 3. La primera página de la tabla CLIENTES

Puedes comparar la Captura 1. con la Captura 3., para comprobar que efectivamente se están mostrando los tres primeros clientes.

Ejemplo 2. Para ver la segunda página

DO PAGINA_SELECT WITH «CLIENTES», «CLI_IDENTI», «CLI_NOMBRE», 3, 2

Captura 4. La consulta que ejecutará el Visual FoxPro

En este caso, la subconsulta devuelve las 3 primeras filas de la tabla CLIENTES. Y la condición en la cláusula WHERE es que el valor de la columna CLI_IDENTI no se encuentre ahí. En otras palabras, se excluirán de la tabla CLIENTES sus tres primeras filas. Eso implica que el SELECT principal tomará las 3 primeras filas, empezando a contar desde la cuarta fila de la tabla CLIENTES. Ingenioso ¿verdad?

Captura 5. La segunda página de la tabla CLIENTES

Ejemplo 3. Para ver la tercera página

DO PAGINA_SELECT WITH «CLIENTES», «CLI_IDENTI», «CLI_NOMBRE», 3, 3

Captura 6. La consulta que ejecutará el Visual FoxPro

Aquí, la subconsulta devuelve las 6 primeras filas de la tabla CLIENTES. Y la condición en la cláusula WHERE es que el valor de la columna CLI_IDENTI no debe encontrarse en ninguna de esas 6 filas. Son excluidas. Por lo tanto el TOP 3 del SELECT principal mostrará las filas 7, 8, y 9.

Captura 7. La tercera página de la tabla CLIENTES

Y así podríamos continuar con las siguientes páginas. Para hacerlo corto, veamos la última página que tiene datos, que en nuestro ejemplo es la página número 6.

Ejemplo 4. Para ver la sexta página

DO PAGINA_SELECT WITH «CLIENTES», «CLI_IDENTI», «CLI_NOMBRE», 3, 6

Captura 8. La consulta que ejecutará el Visual FoxPro

Captura 9. La sexta página de la tabla CLIENTES

Nuestra tabla de CLIENTES tiene 16 filas (como puedes comprobar volviendo a mirar la Captura 1.). En la Captura 8. las primeras 15 filas son excluidas por la condición que se ha puesto en la cláusula WHERE. Por lo tanto se deberían mostrar las siguientes 3 filas. Pero como solamente queda una fila, ya que la tabla tiene 16 filas y 15 filas fueron excluidas, se mostrará una sola fila, tal y como puedes ver en la Captura 9.

Con estos ejemplos, hemos verificado que el PROCEDURE que se escribió en el Listado 3. funciona perfectamente bien.

Conclusión:

Traer todas las filas de una tabla muchas veces no es práctico ni recomendable, sobre todo cuando esas filas deben ser mostradas a los usuarios, porque ningún usuario estará mirando miles y miles de filas.

Una técnica para mostrar solamente unas cuantas filas, y siempre la misma cantidad de filas, es la paginación.

Mediante esta técnica se divide imaginariamente a la tabla en partes iguales, cada una de esas partes recibe el nombre de página.

La cantidad de filas de cada página la determina el programador, según lo que sea más adecuado a sus necesidades.

Por ejemplo, cada página podría tener 50 filas. En la grilla se le muestran las 50 primeras filas de la tabla. Si quiere ver las siguientes 50 filas entonces debe hacer clic en un botón y allí vería desde la fila 51 hasta la fila 100. Si quiere ver las siguientes 50 filas entonces debe hacer clic en el botón y allí vería desde la fila 101 hasta la fila 150. Y así sucesivamente.

Desde luego que también podría tener un botón para ver la página anterior.

De esta manera, nunca se extraerían de la tabla más de 50 filas y en la grilla por lo tanto, nunca se verían más de 50 filas.

Los motores SQL tienen nativamente una cláusula que permite hacer paginación. Lamentablemente, ese no es el caso con Visual FoxPro. Pero se puede escribir un PROCEDURE que permita hacer paginación, tal y como se mostró en el Listado 3.

La paginación es muy, pero muy, importante. Deberías emplearla en cada ocasión posible.

Artículos relacionados:

De DBF a SQL (1). Introducción

De DBF a SQL (2). Reemplazando comandos

De DBF a SQL (3). Entendiendo a los cursores

De DBF a SQL (4). Ejemplos de usar SELECT con una sola tabla

De DBF a SQL (5). Las funciones agrupadas

De DBF a SQL (6). Agrupando filas

De DBF a SQL (7). Poniéndoles condiciones a los grupos

De DBF a SQL (8). Ordenando las filas

De DBF a SQL (9). Uniendo tablas

De DBF a SQL (10). Obteniendo las primeras filas de una tabla

De DBF a SQL (11). Relacionando una tabla con otra tabla

De DBF a SQL (12). Relacionando una tabla consigo misma

De DBF a SQL (13). Relacionando a varias tablas entre sí

De DBF a SQL (14). Más sobre el uso de DISTINCT

De DBF a SQL (15). Usando subconsultas

De DBF a SQL (16). Más sobre las subconsultas

De DBF a SQL (17). Ejemplos de subconsultas

De DBF a SQL (19). Hallando los porcentajes sobre un total

De DBF a SQL (20). Los operadores especiales de comparación

De DBF a SQL (21). La técnica de los dos cursores

De DBF a SQL (22). Optimizando el uso del operador de comparación especial IN

De DBF a SQL (23). Usando la función CAST()

De DBF a SQL (24). Buscando texto

De DBF a SQL (25).  Creando tablas y cursores

De DBF a SQL (26). INSERT, UPDATE, y DELETE, con subconsultas

De DBF a SQL (27). Entendiendo Cliente/Servidor

De DBF a SQL (28). Conectándose a un Servidor

De DBF a SQL (29). Las cadenas de conexión ODBC a los motores SQL más populares 

De DBF a SQL (30). Conectándose mediante ADO a las bases de datos

De DBF a SQL (31). Optimizando la escritura de los SELECT

De DBF a SQL (32). Mejorando la estética de los SELECT 

De DBF a SQL (33). Usando la función SQLEXEC()

De DBF a SQL (34). Enviándole parámetros a la función SQLEXEC()

El índice del blog VFPavanzado