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:
- É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)
- @notulisias:
- É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
- 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()
oCRYPT_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:
- Cambie el rango (como "Módulo") de 86400 a la mitad: 43200
- Recalcule el MMI (puede usar los mismos valores "coprime" que "Integer"): 39539 (igual que antes)
- Agregue
28800
al segundo parámetro deDATEADD
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í .
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 typeuniqueidentifier
; - el valor se convierte con el
cast
para ser utilizado como semilla en la funciónrand([seed])
para generar un valorfloat
pseudoaleatorio de 0 a 1 , y como la semilla siempre es única, el valor de retorno también es único.
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 paraRAND
. 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 delCHECKSUM
: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 paraRAND
: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étodoNEWID
es que tiene control total sobre la secuencia aleatoria. No puede controlar lo queNEWID
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 usandoPARTITION 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
deMD5
resulta en 122 colisiones.RAND
de esteCHECKSUM
resulta en 246 colisiones. Cuando se probó con números de fila de 1 a 100,000CHECKSUM
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 claseRNGCryptoServiceProvider
. - 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