DotNetcr.com
Si deseas hacer un intercambio de links con DotNetcr, escríbenos aquí
Recibe las actualizaciones vía RSS
Te invitamos a unirte en nuestras redes
   http://www.facebook.com/DotNetcr
   http://www.twitter.com/dotnetcr

Como generar correctamente un número random en SQL Server

Por royrojas | 11/25/2009 | Visitas 7,324 | Voto 4.00
Es cierto que SQL Server tiene la función RAND(), la cual genera un número aleatorio, pero este no funciona correctamente o por lo menos como uno lo espera.
Categorías : SQL Server

Es cierto que SQL Server tiene la función RAND(), la cual genera un número aleatorio, pero este no funciona correctamente o por lo menos como uno lo espera.

Por ejemplo RAND() si es ejecutado en transacciones distintas funciona perfectamente pero si es ejecutado varias veces en una misma transacción siempre nos va a retornar el mismo valor, por lo tanto el random no funciona.

Para probar esto que acabo de decir vamos a abrir el Management Studio y en un query nuevo hacemos

   SELECT newid() AS 'New id',
   RAND() AS 'Random',
   CHECKSUM(newid()) AS 'Checksum'

Resultado


New Id Random Checksum
1 F3201996-A5E7-4B44-BDDE-FFF2A2499AB1 0.542140206197715 133238726

Resultado siguiente ves que se ejecuta


New Id Random Checksum
1 41B78E4A-9F73-47E0-8721-2190E699E696 0.216229945261277  926182060

Hasta aquí todo bien, las dos veces se ejecutó correctamente el random, como debe de ser, pero si se ejecuta varias veces en la misma transacción la historia es otra

   SELECT TOP 5 newid() AS 'New id',
   RAND() AS 'Mal Random',
   CHECKSUM(newid()) AS 'Checksum'
   from sys.tables


New Id Mal Random Checksum
1 C797611C-356C-47E4-97AD-14B331CECD7D 0.029692678590302 1529445979
2 12600DA6-B399-4F31-9BED-186EECFAA896 0.029692678590302 -1163175142
3 7691D246-73DE-4DD6-944B-0FA3523F0890 0.029692678590302 1893578383
4 69D663F5-0F40-4732-97FE-CB7F85B22E39 0.029692678590302 526397255
5 F82D3E07-66BF-4579-95D6-C745D9FAAF6E 0.029692678590302 -1752607711

Como podemos ver el valor Random siempre es el mismo, esto se debe a que si a la función Random el seed que utiliza SQL para generar el random es siempre el mismo, el seed de la transacción, por lo tanto el valor retorno siempre es el mismo. Entonces cómo se puede generar un valor random correcto?

En los query de ejemplo podemos ver la columna Checksum, la cual nos está retornando valores diferente en cada resultado, ya sea en transacciones distintas o en la misma transacción. Aquí está la clave para nuestro random.

New Id es un valor que genera SQL tomando como base el MAC address de la tarjeta de red y el reloj de la computadora, esto nos genera un string muy largo pero siempre distinto. Si a este valor le aplicamos la función checksum [  checksum(newid())  ] nos genera un valor numérico entero, que en algunos casos puede ser negativo. Si ocupamos que nuestro valor random sea un numérico entero positivo simplemente le aplicamos la funcion absolute [  abs(checksum(newid()))  ]

Entonces si ahora combinamos estas tres funciones de SQL obtendremos el random que necesitamos

   SELECT  TOP 5
   RAND() AS 'Mal Random',
   abs(checksum(newid())) AS 'RANDOM'
   from sys.tables

Resultado


Mal Random RANDOM
1 0.747613544929705 149303544
2 0.747613544929705 2063275895
3 0.747613544929705 1150964410
4 0.747613544929705 1372336738
5 0.747613544929705 2115100305

Area de Comentarios
Por Anónimo - Fecha: 2010/01/25 02:09 PM
hola, esta interesante el articulo pero tengo una duda, esto es una pulga de SQL? o es asi correcto?, ya que no tiene sentido que una funcion random no funcione varias veces en una misma consulta
Por Anónimo - Fecha: 2010/01/28 09:36 PM
creo que la funcion random es valida por session por eso cuando se ejecuta en una mismo select es el mismo para todos los registros, por esto esta forma que se menciona aqui es la correcta
Por Anónimo - Fecha: 2010/07/30 01:24 PM
interesante!!
Por Anónimo - Fecha: 2011/04/09 06:29 PM
has dado en el clavo
Por Anónimo - Fecha: 2011/08/05 11:41 AM
Esta interesante el articulo pero no le encuentro utilidad...
Por Anónimo - Fecha: 2011/09/21 11:08 AM
Es mejor esta:

SELECT ABS(CAST(NEWID() as binary(3)) % 9999)
--para un número de 1 a 4 dígitos :P
Ingrese su Comentario
Comentario
Para poder votar debe estar registrado en DotNetcr.com
Solo queda registrado el primer voto enviado
Voto


Últimos Recursos
thesondemon
ibarra
dsevic
Eur
jota
juanjoguardiola
PER 237
MEX 236
CRI 185
COL 117
ESP 104
ARG 87