Hola, chicos,
Buenas tardes.

En esta publicación, demostraré cómo sortear una limitación de SQL Server, que es el uso de la función RAND() en funciones UDF, para que pueda generar valores aleatorios y aplicarlos a una tabla. Si intenta hacerlo, SQL Server devolverá este mensaje de error:

Mensaje 443, Nivel 16, Estado 1, Procedimiento fncGera_Password, Línea 50
Uso no válido de un operador de efecto secundario 'rand' dentro de una función.

Para solucionar este problema, hay varias formas, pero mencionaré las dos más sencillas a continuación.

Cree una vista devolviendo la función RAND()

Una alternativa sencilla para solucionar este problema es crear una vista utilizando la función RAND(), a la que se puede acceder mediante la función UDF. Vea a continuación cómo hacerlo:

CREATE VIEW dbo.vwRand
AS SELECT RAND() AS [Rand]
GO

En un uso más simple. simplemente cambie su función UDF para que en lugar de usar la función RAND(), haga SELECT [rand] FROM vwRand.

Ejemplo:

-- Número aleatório entre 0 e 10, podendo ser utilizado dentro de função UDF
SELECT CAST((SELECT [rand] FROM vwRand) * 10 AS INT)

Para generar datos aleatorios a partir de un conjunto de resultados, puedes hacer algo como esto:

SELECT
    DATEADD(DAY, (SELECT [Rand] FROM vwRand) * 12000, '1980-01-01') AS Dt_Nascimento,
    DATEADD(DAY, (SELECT [Rand] FROM vwRand) * 12000, '1980-01-01') AS Dt_Nascimento2,
    DATEADD(DAY, (SELECT [Rand] FROM vwRand) * 12000, '1980-01-01') AS Dt_Nascimento3,
    DATEADD(DAY, (SELECT [Rand] FROM vwRand) * 12000, '1980-01-01') AS Dt_Nascimento4,
    RIGHT(REPLICATE('0', 11) + CAST(CAST((SELECT [Rand] FROM vwRand) * 99999999999 AS BIGINT) AS VARCHAR(11)), 11) AS CPF1,
    RIGHT(REPLICATE('0', 11) + CAST(CAST((SELECT [Rand] FROM vwRand) * 99999999999 AS BIGINT) AS VARCHAR(11)), 11) AS CPF2,
    RIGHT(REPLICATE('0', 11) + CAST(CAST((SELECT [Rand] FROM vwRand) * 99999999999 AS BIGINT) AS VARCHAR(11)), 11) AS CPF3,
    RIGHT(REPLICATE('0', 11) + CAST(CAST((SELECT [Rand] FROM vwRand) * 99999999999 AS BIGINT) AS VARCHAR(11)), 11) AS CPF4

Los datos aleatorios se generan de esta manera:

Esta solución parece haber resuelto nuestro problema. Parece...

Como puedes ver, para generar 1 valor aleatorio, esta solución satisface perfectamente nuestras necesidades, pero al utilizar una tabla preexistente para generar varios registros aleatorios, el resultado no salió como se esperaba, ya que solo se generó 1 registro aleatorio y los demás se repiten en las otras filas de la tabla.

Reemplazo del uso de la función RAND() en su UDF

Esta solución es más sencilla de implementar y tiene más rendimiento, pero analicemos si realmente cumple con nuestros requisitos. Básicamente consiste en crear una nueva función UDF con el siguiente código, que simula el comportamiento aleatorio de la función RAND(), y utilizarla en tu UDF.

Código fuente de la nueva función UDF que genera datos aleatorios:

IF (OBJECT_ID('dbo.fncRand') IS NOT NULL) DROP FUNCTION dbo.fncRand
GO

CREATE FUNCTION dbo.fncRand(@Numero BIGINT)
RETURNS BIGINT
AS
BEGIN
    RETURN (ABS(CHECKSUM(PWDENCRYPT(N''))) / 2147483647.0) * @Numero
END
GO

Y el resultado de la ejecución se ve así:

Probémoslo ahora, generando datos ficticios para probar:

/*
Cálculo da data: 1 a 12.000 dias após 01/01/1980 (+- 32 anos)
Cálculo do CPF: Número aleatório entre 0 e 99999999999
*/

SELECT
    DATEADD(DAY, dbo.fncRand(12000), '1980-01-01') AS Dt_Nascimento,
    DATEADD(DAY, dbo.fncRand(12000), '1980-01-01') AS Dt_Nascimento2,
    DATEADD(DAY, dbo.fncRand(12000), '1980-01-01') AS Dt_Nascimento3,
    DATEADD(DAY, dbo.fncRand(12000), '1980-01-01') AS Dt_Nascimento4,
    RIGHT(REPLICATE('0', 11) + CAST(dbo.fncRand(99999999999) AS VARCHAR(11)), 11) AS CPF1,
    RIGHT(REPLICATE('0', 11) + CAST(dbo.fncRand(99999999999) AS VARCHAR(11)), 11) AS CPF2,
    RIGHT(REPLICATE('0', 11) + CAST(dbo.fncRand(99999999999) AS VARCHAR(11)), 11) AS CPF3,
    RIGHT(REPLICATE('0', 11) + CAST(dbo.fncRand(99999999999) AS VARCHAR(11)), 11) AS CPF4

Y nuestra prueba final, que consiste en utilizar una tabla para generar varios registros aleatorios:

Como puede ver, utilizando esta nueva UDF, fue posible generar datos aleatorios para N registros en una tabla, tiene más rendimiento y su uso también es más sencillo.

Espero que te haya gustado este consejo y nos vemos en el próximo post.
¡Abrazo!