Hola a todos,
lo que pasa es que estoy haciendo una aplicación de un sorteo y necesito tener un numero de ganadores X.
lo que hago es insertar los números de las personas que entran al sorteo según entran (1,2,3,4,...), y cuando es el momento de hacer el sorteo utilizo un update rand y me funciona bien, pero se me repiten los números osea aparecen varios ganadores con números repetidos puse un unique a la tabla pero da igual me tira error de numero duplicado, será que alguien en el foro sabrá como solucionar esto?
los códigos son
CREATE PROCEDURE sorteo(IN turnos int(100)
UPDATE sorteo
SET turno = FLOOR(rand() * turnos) + 1
Gracias de antemano
Creo que puede que lo estés enfocando mal. Igual deberías hacer algo asi como seleccionar los usuarios con un limite, que sería tu número de ganadores, y sacar los datos ordenarlos por rand();
Creo que el buen enfoque sería algo así:
Select * from usuarios order by rand() limit X;
Donde X sería el número de gnadores. Si necesitas updatear algún campo usas el resultado de eso como entrada de los que vas a updatear.
@elshotta (https://underc0de.org/foro/index.php?action=profile;u=10587)
Debería considerar usar una función pseudo-aleatoria que le proporcione su lenguaje de programación o el mismo sistema operativo donde está ahora mismo, pero lo relevante aquí es que debe tener una fuerte entropía para impedir volver a tener números repetidos.
No sé qué lenguaje esté usando, supondré que PHP, pero le dejo otros ejemplos por si acaso le sirve y también para comprender cómo funcionan una capa más abajo de la abstracción.
Usar una formula como esta FLOOR(RAND()*(b-a)+a) significa que deseas obtener un número en un rango de a a b pero no significa que se pueda repetir en algunas iteraciones más, por lo que es mejor usar funciones como las siguiente:
<?php
$bytes = random_bytes(5);
var_dump(bin2hex($bytes));
?>
Esto imprimiría:
string(10) "89429d753c"
Recuerde que está en hexadecimal la salida para que se pueda mostrar de una forma clara para nosotros los humanos, pero debe convertir esos bytes en enteros válidos para poder ser usados.
Se usa la función bin2hex, como le mencioné, para mostrar en un formato claro para nosotros, pero para usar enteros, unpack podría ayudarle:
<?php
$bytes = random_bytes(5);
var_dump(unpack("n", $bytes));
?>
Eso resultaría en:
array(1) {
[1]=>
int(40219)
}
Aquí unas referencias de la misma documentación:
*- https://www.php.net/manual/en/function.random-bytes.php
*- https://www.php.net/manual/en/function.pack.php
Si está usando Python le recomiendo la librería secrets que se encarga de ser un envoltorio entre la función generadora de su sistema operativo:
import secrets
print(secrets.token_hex(5))
Imprimiría:
660fb8c6e6
Referencia:
*- https://docs.python.org/3/library/secrets.html
Y por último usando un archivo especial:
#include <stdio.h>
#include <stdlib.h>
#define MAX_BUFF_SIZE 6
void gen_random(char *buff, int l) {
int i;
FILE *gen;
gen = fopen("/dev/urandom", "rb");
while (l--)
buff += sprintf(buff, "%02x", getc(gen));
buff -= l*2;
fclose(gen);
}
int main(void) {
char buff[MAX_BUFF_SIZE*2];
gen_random(buff, MAX_BUFF_SIZE);
printf("%s\n", buff);
return EXIT_SUCCESS;
}
Imprimiría:
5510aeb233ce
Referencia:
*- https://es.wikipedia.org/wiki//dev/random
~ DtxdF
Gracias por responder,
no es una tarea de la clase de base de datos osea tengo que hacerla en mysql :s
gracias
@elshotta (https://underc0de.org/foro/index.php?action=profile;u=10587)
En general, entonces la formula que te mencioné está bien, pero no tanto considerando que se pueden volver a repetir los números en muchas iteraciones, por lo que debes poner la confianza en el rango, mientras más largo sea, mejor.
Actualizado.
Reflexionando un poco su cuestión; necesita entonces un número aleatorio, que será usado para un torneo o sorteo (es irrelevante), pero el problema es que no es susceptible que no se repita, además el problema debe er solucionado usando puramente SQL.
Bueno, no es necesario cambiar casi nada, entonces usamos un dato único, como el identificador de usuario que mayormente es numérico, es único o es una clave primaria (por ende no se repite), por lo que usaremos de nuevo nuestra formula: FLOOR(RAND()*(b-a)+a) para generar número aleatorios de a a b, sin embargo, el problema es que en la iteraciones se pueden repetir; hagamos algo simple, vamos a sumarlo con el identificador de usuario que es único, por lo que no se volvería a repetir:
SELECT FLOOR(RAND()*(1000-50)+50)+id FROM users;
Las variables aquí son:
A = 50
B = 1000
La tabla = users
La columna = id
Espero le ayude y comente si funcionó o no.
~ DtxdF
Esa si me ha funcionado, gracias!!
Ya puedes dar por solucionado la pregunta
Gracias ;D :D