transact registros obtener number insertar generate generar cadena and aleatorios aleatorio aleatoria sql sql-server sql-server-2008 tsql random-time-generation

registros - sql server random number between 1 and 10



Distinta generación de tiempo aleatorio en el intervalo fijo (7)

Interpretación de la pregunta original:

La pregunta dice:

  • Genere un tiempo aleatorio entre las 8:00 a. M. Y las 8:00 p. M. (Es decir, un intervalo de 12 horas)
  • Debería ser diferente para cada fila (es decir, único en todas las filas)
  • La tabla real tiene alrededor de 2800 registros

Ahora factor en los siguientes puntos:

  • Los datos de muestra muestran solo una fecha
  • Hay 86,400 segundos en 24 horas, por lo tanto, 43,200 segundos en 12 horas

Existe cierta ambigüedad en las siguientes áreas:

  • Lo que es exactamente aleatorio en el contexto de "diferente para cada fila ", dado que no se puede garantizar que los valores verdaderamente aleatorios sean diferentes para cada fila. De hecho, los números verdaderamente aleatorios podrían ser teóricamente iguales para cada fila. Entonces, ¿el énfasis es "aleatorio" o "diferente"? ¿O estamos hablando de órdenes diferentes pero no ordenados secuencialmente (para dar la apariencia de aleatoriedad sin ser realmente aleatorios)?
  • ¿Qué pasa si hay más de 2800 filas? ¿Qué pasa si hay 1 millón de filas?
  • Si puede haber más de 43,200 filas, ¿cómo manejar "diferentes para cada fila " (ya que no es posible tener un único en todas las filas)?
  • ¿La fecha variará alguna vez? Si es así, ¿estamos realmente hablando de "diferente para cada fila por fecha "?
  • Si es "diferente para cada fila por fecha ":
    • ¿Pueden los tiempos de cada fecha seguir el mismo patrón no secuencial? ¿O el patrón debe diferir para cada fecha?
    • ¿Habrá alguna vez más de 43,200 filas para una fecha en particular? Si es así, los tiempos solo pueden ser únicos por cada conjunto de 43,200 filas .

Dada la información anterior, hay algunas formas de interpretar la solicitud:

  1. Énfasis en "al azar": las fechas y el número de filas no importan. Genere tiempos verdaderamente aleatorios que son altamente probables, pero no garantizados , de ser únicos usando uno de los tres métodos que se muestran en las otras respuestas:
    • @notulisias: RAND(CAST(NEWID() AS VARBINARY)) * 43200
    • @Steve Ford: ABS(CHECKSUM(NewId()) % 43201)
    • @Vladimir Baranov: CAST(43200000 * (CAST(CRYPT_GEN_RANDOM(4) as int) / 4294967295.0 + 0.5) as int)
  2. Énfasis en "diferente para cada fila", siempre <= 43,200 filas: si el número de filas nunca supera el número de segundos disponibles, es fácil garantizar tiempos únicos en todas las filas, independientemente de fechas iguales o diferentes, y parecen ser orden aleatorio
  3. El énfasis en "diferente para cada fila" podría ser> 43,200 filas: si el número de filas puede exceder el número de segundos disponibles, no es posible garantizar la exclusividad en todas las filas, pero aún sería posible garantizar la exclusividad en todas las filas. filas de cualquier fecha en particular, siempre que ninguna fecha en particular tenga> 43,200 filas.

Por lo tanto, basé mi respuesta en la idea de que:

  • Incluso si el número de filas para el PO nunca supera los 2800, es más probable que la mayoría de las personas que enfrentan una necesidad similar de aleatoriedad tengan un conjunto de datos más grande para trabajar (es decir, fácilmente podría haber 1 millón de filas, para cualquier número de fechas: 1, 5000, etc.)
  • O los datos de muestra son demasiado simplistas al usar la misma fecha para las 5 filas, o incluso si la fecha es la misma para todas las filas en este caso particular, en la mayoría de los otros casos es menos probable que suceda
  • La unicidad debe ser favorecida sobre la aleatoriedad
  • Si hay un patrón para el orden "aparentemente aleatorio" de los segundos para cada fecha, al menos debe haber un desplazamiento variable al inicio de la secuencia a través de las fechas (cuando las fechas se ordenan secuencialmente) para dar la apariencia de aleatoriedad. entre cualquier pequeña agrupación de fechas.

Responder:

Si la situación requiere tiempos únicos, no se puede garantizar con ningún método de generación de valores verdaderamente aleatorios. Me gusta mucho el uso de CRYPT_GEN_RANDOM por @Vladimir Baranov, pero es casi imposible obtener un único conjunto de valores generados:

DECLARE @Table TABLE (Col1 BIGINT NOT NULL UNIQUE); INSERT INTO @Table (Col1) SELECT CONVERT(BIGINT, CRYPT_GEN_RANDOM(4)) FROM [master].sys.objects so CROSS JOIN [master].sys.objects so2 CROSS JOIN [master].sys.objects so3; -- 753,571 rows

Aumentar el valor aleatorio a 8 bytes parece funcionar:

DECLARE @Table TABLE (Col1 BIGINT NOT NULL UNIQUE); INSERT INTO @Table (Col1) SELECT CONVERT(BIGINT, CRYPT_GEN_RANDOM(8)) FROM [master].sys.objects so CROSS JOIN [master].sys.objects so2 CROSS JOIN [master].sys.objects so3; -- 753,571 rows

Por supuesto, si estamos generando hasta el segundo, entonces solo hay 86,400 de ellos. Reducir el alcance parece ayudar ya que a veces funciona lo siguiente:

DECLARE @Table TABLE (Col1 BIGINT NOT NULL UNIQUE); INSERT INTO @Table (Col1) SELECT TOP (86400) CONVERT(BIGINT, CRYPT_GEN_RANDOM(4)) FROM [master].sys.objects so CROSS JOIN [master].sys.objects so2 CROSS JOIN [master].sys.objects so3;

Sin embargo, las cosas se vuelven un poco más complicadas si las necesidades de exclusividad son por cada día (lo que parece un requisito razonable de este tipo de proyecto, en lugar de único en todos los días). Pero un generador de números aleatorios no sabrá reiniciar cada nuevo día.

Si es aceptable simplemente tener la apariencia de ser aleatorio, entonces podemos garantizar la exclusividad por cada fecha sin:

  • construcciones de bucle / cursor
  • guardar los valores ya utilizados en una tabla
  • usando RAND() , NEWID() o CRYPT_GEN_RANDOM()

La siguiente solución usa el concepto de Inversión Multiplicativa Modular (MMI) que aprendí en esta respuesta: generar ID numéricos únicos aparentemente aleatorios en SQL Server . Por supuesto, esa pregunta no tenía una gama de valores estrechamente definida como la que tenemos aquí con solo 86,400 de ellos por día. Entonces, utilicé un rango de 86400 (como "Módulo") y probé algunos valores "coprimados" (como "Entero") en una calculadora en línea para obtener sus MMI:

  • 13 (MMI = 39877)
  • 37 (MMI = 51373)
  • 59 (MMI = 39539)

Uso ROW_NUMBER() en un CTE, particionado (es decir, agrupado) por CREATED_DATE como medio para asignar un valor a cada segundo del día.

Pero, mientras que los valores generados para los segundos 0, 1, 2, ... y así sucesivamente aparecerán aleatoriamente, en diferentes días ese segundo particular se correlacionará con el mismo valor. Por lo tanto, el segundo CTE (denominado "WhichSecond") cambia el punto de partida para cada fecha convirtiendo la fecha a INT (que convierte las fechas en un desplazamiento secuencial desde 1900-01-01) y luego se multiplica por 101.

DECLARE @Data TABLE ( ID INT NOT NULL IDENTITY(1, 1), CREATED_DATE DATE NOT NULL ); INSERT INTO @Data (CREATED_DATE) VALUES (''2014-10-05''); INSERT INTO @Data (CREATED_DATE) VALUES (''2014-10-05''); INSERT INTO @Data (CREATED_DATE) VALUES (''2014-10-05''); INSERT INTO @Data (CREATED_DATE) VALUES (''2014-10-05''); INSERT INTO @Data (CREATED_DATE) VALUES (''2014-10-05''); INSERT INTO @Data (CREATED_DATE) VALUES (''2015-03-15''); INSERT INTO @Data (CREATED_DATE) VALUES (''2016-10-22''); INSERT INTO @Data (CREATED_DATE) VALUES (''2015-03-15''); ;WITH cte AS ( SELECT tmp.ID, CONVERT(DATETIME, tmp.CREATED_DATE) AS [CREATED_DATE], ROW_NUMBER() OVER (PARTITION BY tmp.CREATED_DATE ORDER BY (SELECT NULL)) AS [RowNum] FROM @Data tmp ), WhichSecond AS ( SELECT cte.ID, cte.CREATED_DATE, ((CONVERT(INT, cte.[CREATED_DATE]) - 29219) * 101) + cte.[RowNum] AS [ThisSecond] FROM cte ) SELECT parts.*, (parts.ThisSecond % 86400) AS [NormalizedSecond], -- wrap around to 0 when -- value goes above 86,400 ((parts.ThisSecond % 86400) * 39539) % 86400 AS [ActualSecond], DATEADD( SECOND, (((parts.ThisSecond % 86400) * 39539) % 86400), parts.CREATED_DATE ) AS [DateWithUniqueTime] FROM WhichSecond parts ORDER BY parts.ID;

Devoluciones:

ID CREATED_DATE ThisSecond NormalizedSecond ActualSecond DateWithUniqueTime 1 2014-10-05 1282297 72697 11483 2014-10-05 03:11:23.000 2 2014-10-05 1282298 72698 51022 2014-10-05 14:10:22.000 3 2014-10-05 1282299 72699 4161 2014-10-05 01:09:21.000 4 2014-10-05 1282300 72700 43700 2014-10-05 12:08:20.000 5 2014-10-05 1282301 72701 83239 2014-10-05 23:07:19.000 6 2015-03-15 1298558 2558 52762 2015-03-15 14:39:22.000 7 2016-10-22 1357845 61845 83055 2016-10-22 23:04:15.000 8 2015-03-15 1298559 2559 5901 2015-03-15 01:38:21.000

Si solo queremos generar tiempos entre las 8:00 AM y las 8:00 PM, solo tenemos que hacer algunos ajustes menores:

  1. Cambie el rango (como "Módulo") de 86400 a la mitad: 43200
  2. Recalcule el MMI (puede usar los mismos valores "coprime" que "Integer"): 39539 (igual que antes)
  3. Agregue 28800 al segundo parámetro de DATEADD como un desplazamiento de 8 horas

El resultado será un cambio a solo una línea (ya que las otras son diagnósticas):

-- second parameter of the DATEADD() call 28800 + (((parts.ThisSecond % 43200) * 39539) % 43200)

Otro medio de cambiar cada día de una manera menos predecible sería hacer uso de RAND() pasando la forma INT de CREATED_DATE en el CTE "WhichSecond". Esto daría un desplazamiento estable por cada fecha dado que RAND(x) devolverá el mismo valor y para el mismo valor de x pasado, pero devolverá un valor diferente y para un valor diferente de x pasado. Significado:

RAND (1) = y1
RAND (2) = y2
RAND (3) = y3
RAND (2) = y2

La segunda vez que se llamó RAND(2) , aún devolvió el mismo valor de y2 que devolvió la primera vez que se llamó.

Por lo tanto, el CTE "WhichSecond" podría ser:

( SELECT cte.ID, cte.CREATED_DATE, (RAND(CONVERT(INT, cte.[CREATED_DATE])) * {some number}) + cte.[RowNum] AS [ThisSecond] FROM cte )

Intento generar un tiempo aleatorio entre las 8:00 a.m. y las 8:00 p.m. para cada fila que se selecciona de un conjunto de datos, sin embargo, siempre obtengo el mismo valor aleatorio para cada fila, quiero que sea diferente para cada fila

Esquema y datos de la tabla:

╔══════╦════════════════╗ ║ ID ║ CREATED_DATE ║ ╠══════╬════════════════╣ ║ ID/1 ║ 26/04/2014 ║ ║ ID/2 ║ 26/04/2014 ║ ║ ID/3 ║ 26/04/2014 ║ ║ ID/4 ║ 26/04/2014 ║ ║ ID/5 ║ 26/04/2014 ║ ╚══════╩════════════════╝

Сurrent instrucción SQL:

SELECT [ID] , MyFunction.dbo.AddWorkDays(14, [CREATED_DATE]) AS [New Date] , CONVERT(VARCHAR, DATEADD(MILLISECOND, CAST(43200000 * RAND() AS INT), CONVERT(TIME, ''08:00'')), 114) AS [New Time] FROM [RandomTable]

Resultados actuales (la misma hora para cada fila en la columna [New Time] ):

╔══════╦════════════════╦════════════════╗ ║ ID ║ New Date ║ New Time ║ ╠══════╬════════════════╬════════════════╣ ║ ID/1 ║ 10/05/2014 ║ 09:41:43 ║ ║ ID/2 ║ 10/05/2014 ║ 09:41:43 ║ ║ ID/3 ║ 10/05/2014 ║ 09:41:43 ║ ║ ID/4 ║ 10/05/2014 ║ 09:41:43 ║ ║ ID/5 ║ 10/05/2014 ║ 09:41:43 ║ ╚══════╩════════════════╩════════════════╝

Resultados deseados (tiempo diferente para cada fila en la columna [New Time] ):

╔══════╦════════════════╦════════════════╗ ║ ID ║ New Date ║ New Time ║ ╠══════╬════════════════╬════════════════╣ ║ ID/1 ║ 10/05/2014 ║ 09:41:43 ║ ║ ID/2 ║ 10/05/2014 ║ 15:05:23 ║ ║ ID/3 ║ 10/05/2014 ║ 10:01:05 ║ ║ ID/4 ║ 10/05/2014 ║ 19:32:45 ║ ║ ID/5 ║ 10/05/2014 ║ 08:43:15 ║ ╚══════╩════════════════╩════════════════╝

¿Alguna idea sobre cómo solucionar este problema? Todo lo anterior es solo un ejemplo de datos: mi tabla real tiene alrededor de 2800 registros ( no estoy seguro si eso marcará la diferencia en las sugerencias de cualquier persona ).


Alternativamente, puedes usar:

SELECT DATEADD(s, ABS(CHECKSUM(NewId()) % 43201), CAST(''08:00:00'' AS Time))

El ABS(CHECKSUM(NewId()) % 43201) genera un número aleatorio entre 0 y 43200 . Ver discusión aquí .

SQL Fiddle

Configuración de esquema MS SQL Server 2008 :

Consulta 1 :

SELECT DATEADD(s, ABS(CHECKSUM(NewId()) % 43201), CAST(''08:00:00'' AS Time)) AS [RandomTime] FROM ( VALUES (1), (2), (3), (4), (5) ) Y(A) CROSS JOIN ( VALUES (1), (2), (3), (4), (5) ) Z(A)

Results :

| RANDOMTIME | |------------------| | 16:51:58.0000000 | | 10:42:44.0000000 | | 14:01:38.0000000 | | 13:33:51.0000000 | | 18:00:51.0000000 | | 11:29:03.0000000 | | 10:21:14.0000000 | | 16:38:27.0000000 | | 09:55:37.0000000 | | 13:21:13.0000000 | | 11:29:37.0000000 | | 10:57:49.0000000 | | 14:56:42.0000000 | | 15:33:11.0000000 | | 18:49:45.0000000 | | 16:23:28.0000000 | | 09:00:05.0000000 | | 09:20:01.0000000 | | 11:26:23.0000000 | | 15:26:23.0000000 | | 10:38:44.0000000 | | 11:46:30.0000000 | | 16:00:59.0000000 | | 09:29:18.0000000 | | 09:09:19.0000000 |


Aquí hay otra opción que le da un poco más de control sobre cómo se genera el tiempo. Puede especificar el intervalo entre los tiempos aleatorios. Tampoco hace uso de la función RAND .

DECLARE @StartTime VARCHAR(10) = ''08:00'', @EndTime VARCHAR(10) = ''20:00'', @Interval INT = 5 --(In Seconds) WITH times AS( SELECT CONVERT(TIME, @StartTime) AS t UNION ALL SELECT DATEADD(SECOND, @Interval, t) FROM times WHERE t < @EndTime ) SELECT *, (SELECT TOP 1 t FROM times WHERE d.Id > 0 ORDER BY NEWID()) FROM #data d option (maxrecursion 0)

En otros comentarios :
Si elimina la cláusula WHERE en la subconsulta anterior ( WHERE d.Id > 0 ), se devuelve el mismo valor de tiempo para todas las filas, es decir, el mismo problema que comenzó con


El problema que tuvo OP al usar solo rand() se debe a su evaluación una vez por consulta .

De la documentation :

Si no se especifica, el motor de base de datos de SQL Server asigna un valor inicial al azar. Para un valor inicial especificado, el resultado devuelto es siempre el mismo.

El enfoque que se describe a continuación elimina la optimización y suprime este comportamiento, por lo que rand() se evalúa una vez por fila :

dateadd( second , rand(cast(newid() as varbinary)) * 43200 , cast(''08:00:00'' as time) )

  • newid() genera un valor único de type uniqueidentifier ;
  • el valor se convierte con el cast para ser utilizado como semilla en la función rand([seed]) para generar un valor float pseudoaleatorio de 0 a 1 , y como la semilla siempre es única, el valor de retorno también es único.

SQLFiddle


Hay varios métodos:

  • Genere una tabla con números aleatorios por adelantado y úsela siempre que sea necesario. O tome esta información de alguna fuente acreditada .
  • Varias combinaciones que usan la función NEWID para proporcionar una semilla para RAND . Se debe usar con precaución, porque no hay garantía sobre la distribución de los valores de NEWID. Uno de los mejores métodos para hacerlo más o menos uniformemente distribuido es a través del CHECKSUM : RAND(CHECKSUM(NEWID())) . Lo bueno de este método es que la función NEWID está disponible desde SQL Server 2000.
  • En lugar de utilizar NEWID , digamos, MD5 de alguna columna como semilla para RAND : RAND(CHECKSUM(HASHBYTES(''MD5'', CAST(SomeID AS varbinary(4))))) O simplemente número de fila: RAND(CHECKSUM(HASHBYTES(''MD5'', CAST(ROW_NUMBER() OVER(ORDER BY ...) AS varbinary(4))))) . Este método está disponible desde al menos SQL Server 2005. La principal diferencia con el método NEWID es que tiene control total sobre la secuencia aleatoria. No puede controlar lo que NEWID devuelve y no puede reiniciar la secuencia aleatoria desde el mismo número nuevamente. Si suministra los mismos conjuntos de, digamos, números de fila usando PARTITION BY obtendrá los mismos conjuntos de números aleatorios. Puede ser útil en los casos en que necesite usar la misma secuencia de números aleatorios varias veces. Es posible obtener el mismo número aleatorio para dos semillas diferentes. Lo probé para números de fila de 1 a 1,000,000. MD5 de ellos son todos diferentes. CHECKSUM de MD5 resulta en 122 colisiones. RAND de este CHECKSUM resulta en 246 colisiones. Cuando se probó con números de fila de 1 a 100,000 CHECKSUM tuvo 1 colisión, RAND tuvo 3 colisiones.
  • Otra posibilidad es simplemente implementar su propia función definida por el usuario en T-SQL que genera un número aleatorio utilizando su algoritmo preferido. En este caso, tienes el control total de todo. Por lo general, los generadores pseudoaleatorios tienen que almacenar su estado interno entre invocaciones, por lo que puede terminar teniendo una tabla dedicada que almacena estos datos.
  • Puede escribir su función definida por el usuario usando CLR. En este caso, puede implementar su propio generador o utilizar funciones integradas en .NET, como la clase Random o la clase RNGCryptoServiceProvider .
  • Por último, desde SQL Server 2008 hay una función CRYPT_GEN_RANDOM .

Describiré el último método en detalle, porque creo que es una muy buena solución para SQL Server 2008 y posteriores. Se llama CRYPT_GEN_RANDOM para cada fila del conjunto de resultados, en oposición a RAND , que se llama solo una vez.

CRYPT_GEN_RANDOM (Transact-SQL)

Devuelve un número aleatorio criptográfico generado por la API Crypto (CAPI). El resultado es un número hexadecimal del número especificado de bytes.

Además, CRYPT_GEN_RANDOM debería proporcionar valores aleatorios mucho mejores que RAND . Mejor en términos de distribución y cripto-fuerza. Ejemplo:

(CAST(CRYPT_GEN_RANDOM(4) as int) / 4294967295.0 + 0.5)

Esto genera 4 bytes aleatorios como varbinary . Tenemos que lanzarlos explícitamente a int primero. Entonces el resultado se transforma en un número flotante entre 0 y 1.

Entonces, a la consulta original le gustaría esto:

SELECT ID AS [ID] , MyFunction.dbo.AddWorkDays(14, S.CREATED_DATE) AS [New Date] , CONVERT(VARCHAR, DATEADD(MILLISECOND, CAST(43200000 * (CAST(CRYPT_GEN_RANDOM(4) as int) / 4294967295.0 + 0.5) as int), CONVERT(TIME, ''08:00'')), 114) AS [New Time] FROM RandomTable

Aquí hay un ejemplo independiente que es fácil de copiar y pegar y probar (utilicé la consulta de otra respuesta de @Steve Ford):

SELECT DATEADD(millisecond, CAST(43200000 * (CAST(CRYPT_GEN_RANDOM(4) as int) / 4294967295.0 + 0.5) as int), CAST(''08:00:00'' AS Time)) AS [RandomTime] FROM ( VALUES (1), (2), (3), (4), (5) ) Y(A) CROSS JOIN ( VALUES (1), (2), (3), (4), (5) ) Z(A)

Este es el resultado:

RandomTime 10:58:24.7200000 19:40:06.7220000 11:04:29.0530000 08:57:31.6130000 15:03:14.9470000 09:15:34.9380000 13:46:43.1250000 11:27:00.8940000 14:42:23.6100000 15:07:56.2120000 11:39:09.8830000 08:16:44.3960000 14:23:38.4820000 17:28:31.7440000 16:29:31.4320000 09:09:15.0210000 12:31:09.8370000 11:23:09.8430000 15:35:45.5480000 17:42:49.3390000 08:07:05.4930000 18:17:16.2980000 11:49:08.2010000 10:20:21.7620000 15:56:58.6110000

Adición

Cuando leí la pregunta original, no pensé que fuera realmente necesario garantizar que todos los números aleatorios generados sean únicos. Interpreté la palabra "diferente" en la pregunta como algo vagamente opuesto a ver el mismo número en cada fila del resultado que se ve al usar un simple SELECT RAND() . Creo que en muchos casos no importa si hay pocos números aleatorios colisionantes. En muchos casos, sería el comportamiento correcto.

Entonces, entiendo que cuando hay una necesidad de una secuencia de números aleatorios únicos , es en un sentido equivalente a la siguiente tarea. Tenemos un conjunto de valores / filas, por ejemplo, un conjunto de ID únicos o todos los 86400 segundos de un día o 2800 filas para un día determinado. Queremos mezclar estos valores / filas. Queremos reorganizar estas filas en un orden aleatorio.

Para barajar el conjunto de filas dado, simplemente necesitamos ORDER BY números aleatorios (estos números aleatorios pueden tener una cantidad razonable de colisiones aquí). Se pueden generar números aleatorios por cualquier método. Algo como esto:

ROW_NUMBER() OVER ([optional PARTITION BY ...] ORDER BY CRYPT_GEN_RANDOM(4))

o literalmente

SELECT ... FROM ... ORDER BY CRYPT_GEN_RANDOM(4)

dependiendo de dónde y cómo se usa.


Prueba esto:

Declare @t table(ID int,CREATED_DATE datetime) insert into @t values (1 , ''04/26/2014''), (2 , ''04/26/2014''), (3 , ''04/26/2014''), (4 , ''04/26/2014'') ;WITH CTE AS ( SELECT *,CONVERT(VARCHAR, DATEADD(SECOND, RAND(CAST(NEWID() AS VARBINARY)) * 43200, CAST(''08:00:00'' AS TIME)),114) AS [New Time] FROM @t WHERE ID=1 UNION ALL SELECT *,CONVERT(VARCHAR, DATEADD(SECOND, RAND(CAST(NEWID() AS VARBINARY)) * 43200, CAST(''08:00:00'' AS TIME)), 114) FROM @t WHERE ID>1 AND ID<=5 ) SELECT * FROM CTE


Todas,

Pensé que compartiría la respuesta a mi pregunta. No recuerdo exactamente dónde encontré los detalles, creo que fue a través de uno de los enlaces proporcionados por sgeddes.

Utilicé la siguiente consulta para obtener un tiempo aleatorio entre 8am y 7:55 pm (aproximadamente)

SELECT convert(varchar,CONVERT(varchar, DATEADD(ms, dbo.MyRand(335 ,830) * 86400, 0), 114),114)

La función MyRand está a continuación:

SET ANSI_NULLS ON; GO SET QUOTED_IDENTIFIER ON; GO CREATE FUNCTION dbo.myRand(@Min INT, @Max INT) RETURNS decimal(18,15) AS BEGIN DECLARE @BinaryFloat BINARY(8) SELECT @BinaryFloat = CAST(Id AS BINARY) FROM vwGuid DECLARE @PartValue TINYINT, @Mask TINYINT, @Mantissa FLOAT, @Exponent SMALLINT, @Bit TINYINT, @Ln2 FLOAT, @BigValue BIGINT, @RandomNumber FLOAT SELECT @Mantissa = 1, @Bit = 1, @Ln2 = LOG(2), @BigValue = CAST(@BinaryFloat AS BIGINT), @Exponent = (@BigValue & 0x7ff0000000000000) / EXP(52 * @Ln2) WHILE @Part <= 8 BEGIN SELECT @PartValue = CAST(SUBSTRING(@BinaryFloat, @Part, 1) AS TINYINT), @Mask = WHILE @Mask > 0 BEGIN IF @PartValue & @Mask > 0 SET @Mantissa = @Mantissa + EXP(-@Bit * @Ln2) SELECT @Mask = @Mask / 2 END END SET @RandomNumber = CASE @Exponent WHEN 0 THEN 0 ELSE CAST(@Exponent AS FLOAT) / 2047 END RETURN CAST((@RandomNumber * (@Max - @Min)) + @Min AS DECIMAL(18,15)) END GO END

Espero que esto ayude. No he leído muchas de las respuestas anteriores, así que me disculpo si alguien tiene una respuesta mejor, así es como lo resolví.

Gracias