No es una actividad regular, pero de vez en cuando me encuentro con la necesidad de recuperar información aleatoria en una base de datos MySQL. En este artículo te mostraré dos técnicas que he utilizado y que te pueden ser de utilidad.
Hablaremos de:
- Cómo recuperar un registro en una posición aleatoria y
- Cómo recuperar registros ordenados de forma aleatoria
Recuperar un registro en una posición aleatoria (random)
En alguna ocasión me encontré con el requerimiento para recuperar un ticket para la premiación de un sorteo, así que tuve que ingeniar una forma de seleccionar un solo registro en aleatorio. El código que pongo a continuación es una versión simplificada de lo que me pareció más eficiente:
-- Primero contamos cuantos registros cumplen con este criterio SELECT COUNT(Id) INTO @count FROM Tickets WHERE IdSorteo = 1; -- Calculamos la posición aleatoria SET @count = FLOOR(@count * RAND() + 1); -- Y recuperamos la información del ticket SELECT * FROM Tickets WHERE IdSorteo = 1 LIMIT @count, 1;
Para comprenderlo mejor, vamos a analizarlo en 3 pasos:
Paso 1: Contar los registros
Para esta técnica necesitamos conocer cuantos registros tenemos disponibles para elegir, por tanto utilizamos la función COUNT para recuperar esta información.
Esta función requiere el nombre de un campo que utilizará para realizar el conteo de los registros y dado que no utilizamos ningún grupo en esta sentencia, el resultado será una única cantidad que se almacenará en la variable @count.
Esta variable @count inicia con una arroba (@), lo que significa que es global y no es necesario definirla (gracias MySQL). Más adelante escribiré un artículo exclusivo para variables.
Si quieres conocer más sobre la función que utilizamos aquí, visita la documentación de MySQL (mientras creo un artículo) en (inglés) https://dev.mysql.com/doc/refman/5.7/en/counting-rows.html
Paso 2: Calcular la posición aleatorea
Esta es la parte interesante. Ahora que sabemos el número total de registros, es muy sencillo crear una fórmula que calcula esta posición aleatoria.
La función RAND nos devuelve un número decimal aleatorio (random) entre 0 y 1, que multiplicamos con el número de registros disponibles, lo que me dará una posición en la tabla. Si quieres conocer más sobre esta función, visita la documentación de MySQL (claro, mientras escribo un artículo) en (inglés) https://dev.mysql.com/doc/refman/5.7/en/mathematical-functions.html#function_rand
Como existe la posibilidad de que el resultado sea CERO, le sumamos UNO para tener una mejor certeza de que recuperaremos un resultado a partir del registro número UNO.
Dado que lo que necesitamos es el número de registro, con la función FLOOR tomamos este valor decimal y lo convertimos en un número entero. Más información en (inglés) https://dev.mysql.com/doc/refman/5.7/en/mathematical-functions.html#function_floor
Paso 3: Recuperar el registro
Ahora conocemos la posición del registro aleatorio en la variable @count, así que consultamos de nuevo la tabla y utilizamos un “LIMIT @count, 1” al final, esto es para indicarle a MySQL que nos interesa tan solo un registro a partir de esta posición aleatoria.
Fácil, ¿no te parece?
Recuperar registros ordenados de forma aleatoria (random)
En alguna ocasión tuve la necesidad de trabajar con una consulta que me proporcionaba información, pero necesitaba distribuirla de forma aleatoria.
Digamos que tenemos estos tickets en diferentes fechas pero no puedo utilizarlos todos, y quiero procesarlos de tal forma que tenga alguna garantía (aunque diminuta) de que tomaré registros de diferentes días en el mismo mes.
SELECT Id, rand() r FROM Tickets WHERE IdProducto = 1 AND CveFormaPago NOT IN ('R','J','C') AND DATE(FechaEmision) BETWEEN '20190101' AND '20190131' ORDER BY r ;
Esta es una versión simplificada, pero con esta sentencia puedo recuperar el ID de los registros que cumplen una condición. Observa que anexo una columna que llamé “r” en donde colocaré un valor aleatorio. Al finalizar, MySQL ordenará los registros utilizando los datos aleatorios.
Es posible que existan soluciones más eficientes, pero en mi caso con 200,000 registros tan solo consume 0.386 segundos en procesar la información, así que creo que es lo suficientemente efectiva.
Conclusión
Todos los problemas tienen circunstancias diferentes y estas soluciones podrían no ser adecuadas para lo que estás buscando, pero sin duda te dará una buena idea para encontrar la solución que necesitas.
En ambos problemas utilicé la función RAND para calcular números aleatorios, pero observa que la aplicación fue muy diferente entre una solución y otra.
Déjame un comentario si tienes dudas o conoces otras técnicas que quisieras compartir.
Deja un comentario