Arjuna Aircraft Ident.: F-MBSD | Salut,
Comme beaucoup de personnes qui ont bossé avec SQL Server, j'ai été confronté au problème de la génération d'un nombre aléatoire.
La fonction RAND() de T-SQL fait tout sauf de l'aléatoire, et c'est facilement vérifiable, y compris avec l'exemple de la documentation.
Déjà, au sein d'une même requête, RAND() produit un nombre unique pour toutes les lignes retournées, ce qui est loin d'être utile.
Ensuite, entre deux appels, quelque soit le temps qui se déroule entre eux, si on utilise le même SEED, on se retrouve avec une valeur quelque peut... identique. Le changement est perceptible (quand il l'est) à partir de la 4° ou 5° décimale... C'est peu.
Bref, cette fonction n'est vraiment pas utilisable.
Pourtant, SQL Server dispose d'un autre générateur de nombre aléatoires, mais il n'est pas vraiment utilisable... Parcequ'il ne retourne pas de nombre compris entre 0 et 1, mais un GUID (Identificateur global unique), qui est un nombre de 16... bytes, pas bits ! (128 bits).
Déjà, ça fait un peux gros, et en plus, c'est au format peut utilisable pour faire des calculs (que le processeur ne saurait de toute façon pas faire) : "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx".
Ceci dit, une solution simple pour générer un mot de passe aléatoire peut être de faire :
Right(newid(), 12) => 12 caractères hexa-décimaux
Left(newid(), 8) => 8 caractères hexa-decimaux
Ou si vous être parano, vous pouvez toujour faire :
Replace(newid(), '-', '') (32 caractères hexa)
Pour tromper l'ennemi, on peut s'amuser à les regrouper ces caractères 2 par deux, et générer le caractère ASCII associé (en vérifiant que le caractère est bien saisissable au clavier ! )
Pour ce faire, on pourra créer ces deux fonctions (je n'ai pas trouvé de moyen de convertir une chaîne hexa en decimal) :
Code :
- create function hexToDec
- (
- @val char(1)
- )
- returns tinyint
- as
- begin
- declare @tmp tinyint
- select @tmp = case
- when @val between '0' and '9' then cast(@val as tinyint)
- when @val = 'A' then 10
- when @val = 'B' then 11
- when @val = 'C' then 12
- when @val = 'D' then 13
- when @val = 'E' then 14
- when @val = 'F' then 15
- end
- return(@tmp)
- end
- go
- create procedure CreatePassword
- (
- @nbChar tinyint,
- @password varchar(255) output
- )
- as
- begin
- declare @cptGuidChar tinyint
- declare @guid as char(32)
- declare @ascii as tinyint
- set @password = ''
- set @cptGuidChar = 0
- while len(@password) < @nbChar
- begin
- if @cptGuidChar = 0
- begin
- select @guid = Replace(Cast(newid() as char(36)), '-', '')
- set @cptGuidChar = 32
- end
- set @ascii = dbo.hexToDec(substring(@guid, @cptGuidChar, 1)) * 16 + dbo.hexToDec(substring(@guid, @cptGuidChar - 1, 1))
- set @cptGuidChar = @cptGuidChar - 2
- set @password = rtrim(@password + (case
- -- ! " # $ % & ' ( ) * + ' - . /
- when @ascii between 33 and 47 then char(@ascii)
- -- 0 1 2 3 4 5 6 7 8 9
- when @ascii between 48 and 57 then char(@ascii)
- -- : ; < = > ? @
- when @ascii between 58 and 64 then char(@ascii)
- -- A B C D E F G H I J K L M N O P Q R S T U V W X Y Z
- when @ascii between 65 and 90 then char(@ascii)
- -- [ \ ] ^ _ `
- when @ascii between 91 and 96 then char(@ascii)
- -- a b c d e f g h i j k l m n o p q r s t u v w x y z
- when @ascii between 97 and 122 then char(@ascii)
- -- { | } ~
- when @ascii between 123 and 126 then char(@ascii)
- else ' '
- end))
- end
- end
- go
|
Note: On est obligé d'utiliser une procédure et non pas une fonction pour la génération du mot de passe car l'utilisation de newid() au sein d'une fonction est interdit (fonction non déterministique).
On peut ensuite utiliser la procédure comme suit :
Code :
- declare @pass varchar(255)
- exec CreatePassword 10, @pass output
- select @pass
- exec CreatePassword 10, @pass output
- select @pass
- exec CreatePassword 40, @pass output
- select @pass
- exec CreatePassword 40, @pass output
- select @pass
|
Résultat :
Code :
- vBvmO!dszt
- 3!:*TB(H$4
- " )+D~O>3T&ch9ldi7nX;m|xO_dKf0y:]v0BX`DWn
- @;^4E_@Yv'KVn#Z}1_VI]gf+DTM'W]rht8$rjZOF
|
Ca, c'est du mot de passe incrackable où je ne m'y connais pas !
Vous noterez que la liste des caractères retenus est en commentaire dans la procédure, vous pouvez changer les intervals afin de trouver un bon compris entre du tout alphanumérique et du tout pas bô comme ça
Bon, voilà, on a un générateur de mots de passe vraiment aléatoire (la demi-vie de la génération d'un GUID est d'environ... quelques centaines de milliers d'années, à compter qu'un PC de type Pentium 4 ne fait que ça pendant tout ce temps), donc ce serait bien domage d'obtenir des doublons ou des séquences qui se répètent !
Ceci dit, ça ne résoud pas le problème du genre "bon, j'ai mon select qui me retourne 25000 lignes, et je veux en prendre un au pif".
C'est là qu'intervient cet article trouvé chez Microsoft (et qui a motivé ce topic) :
http://msdn.microsoft.com/library/ [...] sp04c1.asp
Si vous y comprenez quelque chose, tant mieu pour vous, moi je panne rien
Donc, de mon côté, je reprends ma bonne technique utilisé par mon générateur de mot de passe :
Code :
- create procedure doRandomNumber
- (
- @random float output
- )
- as
- declare @tmp numeric(38)
- begin
- declare @guid char(32)
- set @guid = Replace(newid(), '-', '')
- set @tmp = cast(dbo.hexToDec(substring(@guid, 1, 1)) as numeric) +
- cast(dbo.hexToDec(substring(@guid, 2, 1)) as numeric) * cast(16 as numeric) +
- cast(dbo.hexToDec(substring(@guid, 3, 1)) as numeric) * cast(16 as numeric) * cast(16 as numeric) +
- cast(dbo.hexToDec(substring(@guid, 4, 1)) as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) +
- cast(dbo.hexToDec(substring(@guid, 5, 1)) as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) +
- cast(dbo.hexToDec(substring(@guid, 6, 1)) as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) +
- cast(dbo.hexToDec(substring(@guid, 7, 1)) as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) +
- cast(dbo.hexToDec(substring(@guid, 8, 1)) as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) +
- cast(dbo.hexToDec(substring(@guid, 9, 1)) as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) +
- cast(dbo.hexToDec(substring(@guid, 10, 1)) as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) +
- cast(dbo.hexToDec(substring(@guid, 11, 1)) as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) +
- cast(dbo.hexToDec(substring(@guid, 12, 1)) as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) +
- cast(dbo.hexToDec(substring(@guid, 13, 1)) as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) +
- cast(dbo.hexToDec(substring(@guid, 14, 1)) as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) +
- cast(dbo.hexToDec(substring(@guid, 15, 1)) as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) +
- cast(dbo.hexToDec(substring(@guid, 16, 1)) as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) +
- cast(dbo.hexToDec(substring(@guid, 17, 1)) as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) +
- cast(dbo.hexToDec(substring(@guid, 18, 1)) as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) +
- cast(dbo.hexToDec(substring(@guid, 19, 1)) as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) +
- cast(dbo.hexToDec(substring(@guid, 20, 1)) as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) +
- cast(dbo.hexToDec(substring(@guid, 21, 1)) as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) +
- cast(dbo.hexToDec(substring(@guid, 22, 1)) as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) +
- cast(dbo.hexToDec(substring(@guid, 23, 1)) as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) +
- cast(dbo.hexToDec(substring(@guid, 24, 1)) as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) +
- cast(dbo.hexToDec(substring(@guid, 25, 1)) as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) +
- cast(dbo.hexToDec(substring(@guid, 26, 1)) as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) +
- cast(dbo.hexToDec(substring(@guid, 27, 1)) as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) +
- cast(dbo.hexToDec(substring(@guid, 28, 1)) as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) +
- cast(dbo.hexToDec(substring(@guid, 29, 1)) as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) +
- cast(dbo.hexToDec(substring(@guid, 30, 1)) as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) +
- cast(dbo.hexToDec(substring(@guid, 31, 1)) as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) +
- cast(dbo.hexToDec(substring(@guid, 32, 1)) as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(16 as numeric) * cast(4 as numeric)
- set @random = cast(@tmp as float) / 99999999999999999999999999999999999999
- end
- go
|
Ouais, je sais, j'aurais pu faire les calculs au lieu de mettre des * 16 partout...
Et... Ne me demandez pas pourquoi le "99999999999999999999999999999999999999", je ne sais pas pourquoi
J'ai essayé "(16^31 * 5) - 1" comme la fonction est censée faire, mais ça ne marche pas, j'ai des valeurs > 1 (problèmes d'arrondis certainement, le FLOAT perdant énormément de précision)
Execution :
Code :
- declare @val float
- exec doRandomNumber @val output
- select @val
- exec doRandomNumber @val output
- select @val
- exec doRandomNumber @val output
- select @val
- exec doRandomNumber @val output
- select @val
- exec doRandomNumber @val output
- select @val
|
Résultats :
Code :
- 0.79073888734954445
- 0.39270339086289996
- 0.63849267521354258
- 0.50870770027071233
- 0.33877549375235916
|
Voilà, j'espère que ça vous sera utile
Et tout cas, moi j'en avait besoin, donc j'ai pas perdu mon temps en passant 3 heures à écrire cet article, que j'espère vous le trouverez intéressant ^^
Edit:
La procédure stockée que j'ai indiqué, parceque c'est une procédure stockée et non une fonction ne resoud toujours pas la question "bon, j'ai mon select qui me retourne 25000 lignes, et je veux en prendre un au pif"... puisqu'on ne peut pas la faire intervenir dans la requête !
On pourra toujours écrire un curseur qui parcoure le résultat de la requête, compte le nombre de lignes, puis prend la (count * random)ième ligne. Vu le bordel que ça a été pour récupérer le nombre aléatoire, on n'est plus à ça prêt Message édité par Arjuna le 10-06-2005 à 23:21:09
|