J'ai besoin d'un nombre aléatoire différent pour chaque ligne de ma table. Le code apparemment évident suivant utilise la même valeur aléatoire pour chaque ligne.
SELECT table_name, Rand() magic_number
FROM information_schema.tables
Je voudrais obtenir un INT ou un FLOAT de cela. Le reste de l'histoire est que je vais utiliser ce nombre aléatoire pour créer une date aléatoire décalée par rapport à une date connue, par exemple. 1-14 jours décalés à partir d'une date de début.
Ceci est pour Microsoft SQL Server 2000.
Jetez un oeil à SQL Server - Définir des nombres aléatoires qui a une explication très détaillée.
Pour résumer, le code suivant génère un nombre aléatoire compris entre 0 et 13 inclus avec une distribution normalisée:
ABS(CHECKSUM(NewId())) % 14
Pour changer votre gamme, il suffit de changer le nombre à la fin de l'expression. Faites particulièrement attention si vous avez besoin d’une plage comprenant à la fois des nombres positifs et des nombres négatifs. Si vous le faites mal, il est possible de compter deux fois le nombre 0.
Petit avertissement pour les fous de maths dans la salle: il y a un très léger biais dans ce code. CHECKSUM()
donne des chiffres uniformes sur toute la plage du type de données sql Int, ou au moins aussi près que le permet mon test (l'éditeur). Cependant, il y aura un certain biais lorsque CHECKSUM () produira un nombre tout à fait à la fin de cette plage. Chaque fois que vous obtenez un nombre compris entre le nombre entier maximal possible et le dernier multiple exact de la taille de votre plage désirée (14 dans ce cas) avant ce nombre entier maximum, ces résultats sont privilégiés par rapport à la partie restante de votre plage qui ne peut pas être produite. ce dernier multiple de 14.
Par exemple, imaginez que la plage entière du type Int ne soit que de 19. 19 est le plus grand entier possible que vous puissiez contenir. Lorsque CHECKSUM () donne 14-19, ceux-ci correspondent aux résultats 0-5. Ces nombres seraient fortement privilégiés par rapport à 6-13, car CHECKSUM () est deux fois plus susceptible de les générer. C'est plus facile de démontrer cela visuellement. Vous trouverez ci-dessous l'ensemble des résultats possibles pour notre plage entière imaginaire:
Checksum Entier: 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 Plage Résultat: 0 1 2 3 4 5 6 7 8 9 10 11 12 13 0 1 2 3 4 5
Vous pouvez voir ici qu'il y a plus de chances de produire certains chiffres que d'autres: le biais. Heureusement, la plage réelle du type Int est beaucoup plus grande ... à tel point que dans la plupart des cas, le biais est presque indétectable. Cependant, il faut en prendre conscience si vous vous retrouvez déjà confronté à un problème de sécurité grave.
Lorsqu'il est appelé plusieurs fois dans un même lot, Rand () renvoie le même numéro.
Je suggérerais d'utiliser convert (varbinary
, newid()
) comme argument de départ:
SELECT table_name, 1.0 + floor(14 * Rand(convert(varbinary, newid()))) magic_number
FROM information_schema.tables
Il est garanti que newid()
renverra une valeur différente à chaque appel, même au sein du même lot. Son utilisation en tant que valeur de départ donnera alors Prompt Rand () pour donner une valeur différente à chaque fois.
Édité pour obtenir un nombre entier aléatoire de 1 à 14.
Rand(CHECKSUM(NEWID()))
Ce qui précède générera un nombre (pseudo) aléatoire compris entre 0 et 1, exclusif. S'il est utilisé dans une sélection, étant donné que la valeur de départ change pour chaque ligne, un nouveau nombre aléatoire sera généré pour chaque ligne (il n'est toutefois pas garanti de générer un nombre unique par ligne).
Exemple combiné avec une limite supérieure de 10 (produit les nombres 1 à 10):
CAST(Rand(CHECKSUM(NEWID())) * 10 as INT) + 1
Documentation Transact-SQL:
Génération de nombres aléatoires entre 1000 et 9999 inclus:
FLOOR(Rand(CHECKSUM(NEWID()))*(9999-1000+1)+1000)
"+1" - pour inclure les valeurs supérieures (9999 pour l'exemple précédent)
Répondre à l'ancienne question, mais cette réponse n'a pas été fournie auparavant, et j'espère que cela sera utile pour quelqu'un qui trouvera ces résultats via un moteur de recherche.
Avec SQL Server 2008, une nouvelle fonction a été introduite, CRYPT_GEN_RANDOM(8)
, qui utilise CryptoAPI pour produire un nombre aléatoire fort sur le plan cryptographique, renvoyé sous la forme VARBINARY(8000)
. Voici la page de documentation: https://docs.Microsoft.com/en-us/sql/t-sql/functions/crypt-gen-random-transact-sql
Donc, pour obtenir un nombre aléatoire, vous pouvez simplement appeler la fonction et la convertir en un type:
select CAST(CRYPT_GEN_RANDOM(8) AS bigint)
ou pour obtenir un float
compris entre -1 et +1, vous pouvez faire quelque chose comme ceci:
select CAST(CRYPT_GEN_RANDOM(8) AS bigint) % 1000000000 / 1000000000.0
La fonction Rand () générera le même nombre aléatoire si elle est utilisée dans une requête SELECT de la table. La même chose s'applique si vous utilisez une graine pour la fonction Rand. Une autre façon de le faire, utilise ceci:
SELECT ABS(CAST(CAST(NEWID() AS VARBINARY) AS INT)) AS [RandomNumber]
J'ai eu l'information de ici , ce qui explique très bien le problème.
Si vous devez conserver votre graine afin qu'elle génère les "mêmes" données aléatoires à chaque fois, vous pouvez procéder comme suit:
1. Créer une vue qui retourne select Rand ()
if object_id('cr_sample_randView') is not null
begin
drop view cr_sample_randView
end
go
create view cr_sample_randView
as
select Rand() as random_number
go
2. Créez un fichier UDF qui sélectionne la valeur dans la vue.
if object_id('cr_sample_fnPerRowRand') is not null
begin
drop function cr_sample_fnPerRowRand
end
go
create function cr_sample_fnPerRowRand()
returns float
as
begin
declare @returnValue float
select @returnValue = random_number from cr_sample_randView
return @returnValue
end
go
. Avant de sélectionner vos données, définissez la fonction Rand (), puis utilisez l'UDF dans votre instruction select.
select Rand(200); -- see the Rand() function
with cte(id) as
(select row_number() over(order by object_id) from sys.all_objects)
select
id,
dbo.cr_sample_fnPerRowRand()
from cte
where id <= 1000 -- limit the results to 1000 random numbers
Avez-vous une valeur entière dans chaque ligne que vous pourriez transmettre en tant que graine à la fonction Rand?
Pour obtenir un entier compris entre 1 et 14, je crois que cela fonctionnerait:
FLOOR( Rand(<yourseed>) * 14) + 1
select round(Rand(checksum(newid()))*(10)+20,2)
Ici, le nombre aléatoire sera compris entre 20 et 30. round
donnera un maximum de deux décimales.
Si vous voulez des nombres négatifs, vous pouvez le faire avec
select round(Rand(checksum(newid()))*(10)-60,2)
Ensuite, la valeur minimale sera -60 et la valeur maximale sera -50.
essayez d'utiliser une valeur de départ dans le Rand (seedInt). Rand () ne s’exécutera qu’une fois par instruction, c’est pourquoi vous voyez le même nombre à chaque fois.
Si vous n'avez pas besoin que ce soit un entier, mais n'importe quel identifiant unique aléatoire, vous pouvez utiliser newid()
SELECT table_name, newid() magic_number
FROM information_schema.tables
Vous devez appeler Rand () pour chaque ligne. Voici un bon exemple
select ABS(CAST(CAST(NEWID() AS VARBINARY) AS INT)) as [Randomizer]
a toujours travaillé pour moi
sélectionnez newid ()
ou éventuellement cette sélection binary_checksum (newid ())
C'est aussi simple que:
DECLARE @rv FLOAT;
SELECT @rv = Rand();
Et cela mettra un nombre aléatoire entre 0 et 99 dans un tableau:
CREATE TABLE R
(
Number int
)
DECLARE @rv FLOAT;
SELECT @rv = Rand();
INSERT INTO dbo.R
(Number)
values((@rv * 100));
SELECT * FROM R
Le problème que j'ai parfois avec la "Réponse" sélectionnée est que la distribution n'est pas toujours uniforme. Si vous avez besoin d'une distribution très uniforme de nombres aléatoires de 1 à 14 parmi un grand nombre de lignes, vous pouvez procéder de la sorte bien):
SELECT table_name, ntile(14) over(order by newId()) randomNumber
FROM information_schema.tables
Cela fait l’opposé des solutions aléatoires normales en ce sens qu’il garde les nombres séquencés et rend aléatoire l’autre colonne.
Rappelez-vous que ma base de données contient 511 tables (ce qui n’est pertinent que si nous sélectionnons à partir de information_schema). Si je prends la requête précédente et la mets dans une table temporaire #X, puis lance cette requête sur les données résultantes:
select randomNumber, count(*) ct from #X
group by randomNumber
J'obtiens ce résultat en me montrant que mon nombre aléatoire est TRÈS uniformément réparti sur les nombreuses lignes:
DROP VIEW IF EXISTS vwGetNewNumber;
GO
Create View vwGetNewNumber
as
Select CAST(Rand(CHECKSUM(NEWID())) * 62 as INT) + 1 as NextID,
'abcdefghijklmnopqrstuvwxyz0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ'as alpha_num;
---------------CTDE_GENERATE_PUBLIC_KEY -----------------
DROP FUNCTION IF EXISTS CTDE_GENERATE_PUBLIC_KEY;
GO
create function CTDE_GENERATE_PUBLIC_KEY()
RETURNS NVARCHAR(32)
AS
BEGIN
DECLARE @private_key NVARCHAR(32);
set @private_key = dbo.CTDE_GENERATE_32_BIT_KEY();
return @private_key;
END;
go
---------------CTDE_GENERATE_32_BIT_KEY -----------------
DROP FUNCTION IF EXISTS CTDE_GENERATE_32_BIT_KEY;
GO
CREATE function CTDE_GENERATE_32_BIT_KEY()
RETURNS NVARCHAR(32)
AS
BEGIN
DECLARE @public_key NVARCHAR(32);
DECLARE @alpha_num NVARCHAR(62);
DECLARE @start_index INT = 0;
DECLARE @i INT = 0;
select top 1 @alpha_num = alpha_num from vwGetNewNumber;
WHILE @i < 32
BEGIN
select top 1 @start_index = NextID from vwGetNewNumber;
set @public_key = concat (substring(@alpha_num,@start_index,1),@public_key);
set @i = @i + 1;
END;
return @public_key;
END;
select dbo.CTDE_GENERATE_PUBLIC_KEY() public_key;
Mettre à jour ma_table set my_field = CEILING ((Rand (CAST (NEWID () AS varbinary))) * 10))
Nombre compris entre 1 et 10.