web-dev-qa-db-ja.com

TSQL Selectの各行に乱数を生成する方法

テーブルの各行に異なる乱数が必要です。次の一見明白なコードは各行に同じ乱数を使用します。

SELECT table_name, Rand() magic_number 
FROM information_schema.tables 

これからINTかFLOATを取得したいのですが。ストーリーの残りの部分では、この乱数を使用して既知の日付からランダムにオフセットされた日付を作成します。開始日から1-14日のオフセット。

これはMicrosoft SQL Server 2000用です。

291
MatthewMartin

SQL Server - 非常に詳細な説明があるベースの乱数 を見てください。

要約すると、次のコードは正規化された分布で0から13までの乱数を生成します。

ABS(CHECKSUM(NewId())) % 14

範囲を変更するには、式の最後にある数字を変更するだけです。正数と負数の両方を含む範囲が必要な場合は特に注意してください。間違えた場合は、0をダブルカウントすることが可能です。

部屋の中の数学ナットに対する小さな警告:このコードにはごくわずかな偏りがあります。 CHECKSUM()は、sqlのIntデータ型の範囲全体にわたって、あるいは少なくとも私の(エディタの)テストが示すことができるほど近い数値にわたって一様な数になる。ただし、CHECKSUM()がその範囲の一番上の端に数値を生成するときには、いくらか偏りがあります。最大の整数値とその最大の整数値より前の目的の範囲のサイズの最後の正確な倍数(この場合は14)の間の数値を得ると、それらの結果は範囲から得られない残りの部分よりも優先されます。それは14の最後の倍数です。

例として、Int型の範囲全体が19だけであると想像してみてください。19はあなたが保持できる最大の整数です。 CHECKSUM()の結果が14-19の場合、これらは結果0-5に対応します。 CHECKSUM()がそれらを生成する可能性が2倍であるため、これらの数は6/13より重いになります。これを視覚的に示す方が簡単です。以下は、想像上の整数範囲で考えられる結果の全体のセットです。

チェックサム整数:0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 
範囲結果:0 1 2 3 4 5 6 7 8 9 10 11 12 13 0 1 2 3 4 5 

ここで、他のものよりもいくつかの数を生み出す可能性が高いことがわかります。バイアス。ありがたいことに、Int型の実際の範囲はmuchlarge ...ですので、ほとんどの場合、バイアスはほとんど検出できません。ただし、深刻なセキュリティコードのためにこれを実行していることに気付いた場合は、注意が必要です。

454
SQLMenace

1回のバッチで複数回呼び出された場合、Rand()は同じ番号を返します。

シード引数としてconvert(varbinarynewid())を使用することをお勧めします。

SELECT table_name, 1.0 + floor(14 * Rand(convert(varbinary, newid()))) magic_number 
FROM information_schema.tables

newid()は、同じバッチ内であっても、呼び出されるたびに異なる値を返すことが保証されているので、シードとして使用すると、毎回異なる値を与えるようにRand()に促します。

1から14までのランダムな整数を取得するように編集されました。

87
Jeremy Smyth
Rand(CHECKSUM(NEWID()))

上記は、0から1の間の排他的な(疑似)乱数を生成します。 selectで使用すると、シード値は各行ごとに変わるため、各行ごとに新しい乱数が生成されます(ただし、行ごとに一意の番号が生成されることは保証されていません)。

上限の10と組み合わせた場合の例(数値1 - 10)

CAST(Rand(CHECKSUM(NEWID())) * 10 as INT) + 1

Transact-SQLのドキュメント

  1. CAST()https://docs.Microsoft.com/ja-jp/sql/t-sql/functions/cast-and-convert-transact-sql
  2. Rand()http://msdn.Microsoft.com/ja-jp/library/ms177610.aspx
  3. CHECKSUM()http://msdn.Microsoft.com/ja-jp/library/ms189788.aspx
  4. NEWID()https://docs.Microsoft.com/ja-jp/sql/t-sql/functions/newid-transact-sql
65
Aaron Hoffman

1000から9999までの乱数生成

FLOOR(Rand(CHECKSUM(NEWID()))*(9999-1000+1)+1000)

"+ 1" - 上限値を含める(前の例では9999)

34
Vova

古い質問に答えるが、この答えは以前には提供されていないので、これが検索エンジンでこの結果を見つけるのに役立つことを願っています。

SQL Server 2008では、新しい関数CRYPT_GEN_RANDOM(8)が導入されました。この関数はCryptoAPIを使用して暗号的に強い乱数を生成し、VARBINARY(8000)として返されます。これがドキュメントページです。 https://docs.Microsoft.com/ja-jp/sql/t-sql/functions/crypt-gen-random-transact-sql

そのため、乱数を取得するには、関数を呼び出して必要な型にキャストするだけです。

select CAST(CRYPT_GEN_RANDOM(8) AS bigint)

あるいは-1と+1の間のfloatを取得するには、次のようにします。

select CAST(CRYPT_GEN_RANDOM(8) AS bigint) % 1000000000 / 1000000000.0
17
Andrei Tanas

テーブルのSELECTクエリで使用された場合、Rand()関数は同じ乱数を生成します。 Rand関数にシードを使用した場合も同様です。これを実行する代替方法は、これを使用することです。

SELECT ABS(CAST(CAST(NEWID() AS VARBINARY) AS INT)) AS [RandomNumber]

ここで から情報を入手してください 、問題を非常によく説明しています。

11
MicSim

毎回「同じ」ランダムデータを生成するようにシードを保存する必要がある場合は、次の操作を行います。

1。 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。ビューから値を選択するUDFを作成します

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

3。データを選択する前に、Rand()関数をシードしてから、selectステートメントでUDFを使用してください

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
5
Mitselplik

Rand関数にシードとして渡すことができる整数値が各行にありますか?

1から14までの整数を取得するには、これでうまくいくと思います。

FLOOR( Rand(<yourseed>) * 14) + 1
5
CoderDennis
select round(Rand(checksum(newid()))*(10)+20,2)

ここでは、乱数は20から30の間になります。roundは、小数点以下第2位までを表示します。

負の数が必要な場合は、

select round(Rand(checksum(newid()))*(10)-60,2)

最小値は-60、最大値は-50になります。

4
Tirthankar

rand(seedInt)でシード値を使ってみてください。 Rand()はステートメントごとに一度だけ実行されるので、毎回同じ番号が表示されます。

4
northpole

整数ではなく任意のランダムな一意の識別子である必要がない場合は、newid()を使用できます。

SELECT table_name, newid() magic_number 
FROM information_schema.tables
4
4
David
select ABS(CAST(CAST(NEWID() AS VARBINARY) AS INT)) as [Randomizer]

いつも私のために働いてきました

2
theteague

select newid()

または、おそらくこれを選択してくださいbinary_checksum(newid())

2
Chris Klepeis

それは同じくらい簡単です:

DECLARE @rv FLOAT;
SELECT @rv = Rand();

そしてこれはテーブルに0-99の間の乱数を入れるでしょう:

CREATE TABLE R
(
    Number int
)

DECLARE @rv FLOAT;
SELECT @rv = Rand();

INSERT INTO dbo.R
(Number)
    values((@rv * 100));

SELECT * FROM R
2
Rosjier Hall

私が選択した「答え」に関して時々抱えている問題は、配布が常に均等ではないということです。たくさんの行にランダムな1 - 14の非常に均一な分布が必要な場合は、次のようにすることができます(私のデータベースには511のテーブルがあるので、これでうまくいきます。 ):

SELECT table_name, ntile(14) over(order by newId()) randomNumber 
FROM information_schema.tables

この種のものは、数を順番に並べて他の列をランダム化するという意味で、通常のランダム解とは逆になります。

データベースには511個のテーブルがあります(これは、information_schemaから選択したb/cにのみ関係します)。前のクエリを取得してそれを一時テーブル#Xに入れてから、結果のデータに対してこのクエリを実行するとします。

select randomNumber, count(*) ct from #X
group by randomNumber

私はこの結果を得ました。私の乱数は多くの行に均等に分布していることを示しています。

enter image description here

2
Trevor
    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;
1
ichak khoury

My_table set my_field = CEILING((Rand(CAST(NEWID()AS varbinary))* 10))を更新します。

1から10までの数値.

0
user3478586