2011-04-01 78 views
10

¿Cómo puedo seleccionar una fecha aleatoria dentro de un rango inclusivo específico, digamos '1950-01-01' y '1999-12-31' con SQL Server?Seleccione una fecha aleatoria dentro del rango específico

+0

¿Está tratando de generar datos para varias filas al mismo tiempo, o solo una sola fecha? Me pregunto si estás tratando de construir algunos datos de prueba para insertar en una tabla. – Jeff

+0

Hola Jeff. Necesito fechas aleatorias dentro de un rango para ejecutar un ciclo y completar una tabla de prueba con fechas de nacimiento aleatorias. :) –

+0

¿Cuántas filas de datos necesitas? –

Respuesta

12

Esto le dará 1000 filas de datos para insertar.

DECLARE @D1 DATE = '19500101' 
DECLARE @D2 DATE = '19991231' 

    ;WITH E00(N) AS (SELECT 1 UNION ALL SELECT 1), 
     E02(N) AS (SELECT 1 FROM E00 a, E00 b), 
     E04(N) AS (SELECT 1 FROM E02 a, E02 b), 
     E08(N) AS (SELECT 1 FROM E04 a, E04 b), 
     E16(N) AS (SELECT 1 FROM E08 a, E08 b), 
     E32(N) AS (SELECT 1 FROM E16 a, E16 b), 
    cteTally(N) AS (SELECT ROW_NUMBER() OVER (ORDER BY N) FROM E32) 
    SELECT TOP 1000 
    DATEADD(DAY,ABS(CHECKSUM(NEWID())) % (1+DATEDIFF(DAY,@D1,@D2)),@D1) 
    FROM cteTally 

NB: Esta respuesta utilizado originalmente ABS(CAST(CRYPT_GEN_RANDOM(4) AS INT)) para generar los números aleatorios. A diferencia de RAND() que solo se evalúa una vez por declaración, esto se evalúa una vez por fila, por lo que funcionaría.

Sin embargo, parece que el Optimizador de consultas no se da cuenta de esto y lo trata como una constante. A los efectos de generar datos aleatorios, esto probablemente no importe (a menos que esté rellenando una columna restringida por una clave externa)

pero acabo de probar la alternativa ABS(CHECKSUM(NEWID())) para ver si hubo algún beneficio de rendimiento de uno sobre el otro .

Las velocidades típicas para generar 1.000.000 de filas utilizando la tabla de números de arriba y elige el valor MAX (para evitar la sobrecarga de devolver todas estas filas para el cliente)

ABS(CAST(CRYPT_GEN_RANDOM(4) AS INT)) 
/*CPU time = 4180 ms, elapsed time = 4395 ms.*/ 

ABS(CHECKSUM(NEWID())) 
/*CPU time = 953 ms, elapsed time = 1163 ms.*/ 

(SELECT 1) /*A constant value just to get a baseline*/ 
/*CPU time = 499 ms, elapsed time = 457 ms.*/ 

Así que a menos que necesite un PRNG criptográficamente seguro que es probablemente mejor evitado!

+0

Hola Martin. Muchas gracias. Parece que si quiero tener incluso '1992-12-31' tengo que declarar @ d2 como '2000-01-01', de lo contrario, la consulta no incluye el último día. –

+0

@nick - Ya lo cambié a '1 + DATEDIFF (DAY, @ D1, @ D2)' para solucionar ese problema. –

+0

Eres simplemente genial :) Gracias por todo el tiempo que me has dedicado. Realmente lo aprecio. Gracias de nuevo Martin. –

15
select DateAdd(d, ROUND(DateDiff(d, '1950-01-01', '1999-12-31') * RAND(), 0), '1950-01-01') 

EDITAR

Si esto va a ser ejecutado como parte de una sentencia que devuelve varias filas o como parte de la actualización, el RAND() devolvería el valor único para todo el conjunto de resultados. Para ese caso, se puede usar RAND (CHECKSUM (NEWID()).

select DateAdd(d, ROUND(DateDiff(d, '1950-01-01', '1999-12-31') * RAND(), 0), '1950-01-01'), 
     DateAdd(d, ROUND(DateDiff(d, '1950-01-01', '1999-12-31') * RAND(CHECKSUM(NEWID())), 0), '1950-01-01') 
from master..spt_values where type = 'P' 
+0

Esto parece estar seleccionado aleatoriamente el 1/1/1950 o el 12/31/1999, pero no entre fechas. – JustinStolle

+0

Hola. Gracias por su respuesta. He intentado con tu consulta pero siempre devuelve uno de esos dos valores como ya está escrito. –

+0

+1 Ahora funciona bien. Gracias;) –

Cuestiones relacionadas