2010-08-20 12 views
9

Après un peu de recherche et de lecture de la documentation, il est clair que vous pouvez écrire des fonctions définies par l'utilisateur dans SQL Server qui sont marquées comme déterministes ou non déterministes selon les fonctions intégrées utilisé dans le corps. RAND() est répertorié sous les fonctions non déterministes (voir msdn article). Alors pourquoi je ne peux pas l'utiliser dans une fonction?Création de fonctions non déterministes dans SQL Server en utilisant RAND()

Répondre

13

Parce qu'il a des effets secondaires.

Les constructions avec des effets secondaires ne sont pas autorisées dans une fonction. L'effet secondaire est de modifier un état interne qui conserve la dernière valeur rand() émise.

Je pense que vous pouvez contourner cela en l'incluant dans une définition de vue puis en sélectionnant dans la vue.

+0

ah, je comprends maintenant! Je n'ai pas pensé au stockage interne du dernier nombre aléatoire. Je peux voir comment cela le distingue des autres fonctions non déterministes. Merci! – BG100

+0

consultez http://sqlfascination.com/tag/randomstring/ Il vous dit exactement comment faire cela. – baash05

19

L'utilisation d'une vue peut fonctionner pour vous.
De Returning Random Numbers from a select statement

CREATE VIEW vRandNumber 
AS 
SELECT RAND() as RandNumber 

La vue est nécessaire parce que, comme vous avez déjà découvert, une UDF ne peut pas utiliser la fonction rand() car cela rendrait la fonction non-determistic. Vous pouvez tromper l'UDF pour accepter un nombre aléatoire en utilisant une vue.

CREATE FUNCTION RandNumber() 
RETURNS float 
AS 
    BEGIN 
    RETURN (SELECT RandNumber FROM vRandNumber) 
    END 

Enfin, vous pouvez utiliser cette fonction dans tout SELECT pour revenir maintenant un nombre aléatoire entre 0 et 1 par ligne:

SELECT dbo.RandNumber(), * 
FROM Northwind..Customers 
+4

+1 Pour l'astuce de vue. Je me suis juste souvenu de ça aussi. Ce n'est pas à cause du déterminisme cependant. 'getdate()' est autorisé dans une fonction. De toute évidence, cette fonction ne peut pas être utilisée lorsqu'une fonction déterministe est requise, telle qu'une colonne calculée persistante. C'est à cause des effets secondaires. L'erreur soulevée est "Utilisation invalide d'un opérateur '' rand '' dans une fonction." –

+0

Merci! J'avais entendu parler de faire cela comme un travail autour de la fonction NEWID(), mais je ne savais pas que cela fonctionnerait aussi bien pour RAND(). – BG100

3

Je trouve cette solution qui ne crée pas une vue:

en gros:

Au lieu de

SET @R = Rand() 

Utilisez

SET @R = ABS(CHECKSUM(PWDENCRYPT(N'')))/2147483647.0 

Dans mon cas, je voulais un nombre compris entre 1 et 10:

ROUND(((10 - 1 -1) * (ABS(CHECKSUM(PWDENCRYPT(N'')))/2147483647.0) + 1), 0)) 

ROUND(((@max - @lower -1) * (ABS(CHECKSUM(PWDENCRYPT(N'')))/2147483647.0) + @lower), 0)) 

Si vous voulez une explication complète: Using (Or Simulating) Rand() In A T-Sql User-Defined Function