2

rand(checksum(newid()))は、乱数を生成するためによく使用されます。

いくつかのテスト データを生成しているときに、次のステートメントを実行しました。

select rand(checksum(newid())) R1, rand(checksum(newid())) R2
from ftSequence(3)

ここで、単一の列とその行の値(引数と同じ数) をftSequence(N)返すテーブル関数です。これを実行すると、非常に期待されるデータが得られました。N1, 2, 3 ... NN

R1                     R2
---------------------- ----------------------
0,817                  0,9515
0,3043                 0,3947
0,5336                 0,7963

次に、各列の合計を見つける必要があり、次のようにしました。

select sum(rand(checksum(newid()))) S1, sum(rand(checksum(newid()))) S2
from ftSequence(3)

驚いたことに、各列に同じ数字が表示されました。

S1                     S2
---------------------- ----------------------
1,2276                 1,2276

なぜそれが起こるのですか?avgminおよびmax集約関数の同じ動作。クエリオプティマイザーですか、それともロジックがありませんか?


コメントの後にさらに観察。

sum(rand(checksum(newid())))CTEまたはサブクエリに配置する

select
    (select sum(rand(checksum(newid()))) from ftSequence(3)) S1,
    (select sum(rand(checksum(newid()))) from ftSequence(3)) S2

また

select sum(R1) S1, sum(R2) S2
from (
    select rand(checksum(newid())) R1, rand(checksum(newid())) R2
    from ftSequence(3)
) R

のようなトリックを行うだけでなく、

select
    sum(rand(checksum(newid()))) S1
    , sum(rand(checksum(newid())) + 0) S2
from ftSequence(3)

働き、異なる値になりました

S1                     S2                    
---------------------- ----------------------
0,7349                 1,478                 

それに満足し、いくつかの異なる行を複数生成する必要があったため、avg(rand(checksum(newid()))) from ftSequence(3)次のことを行いました

select R.*
from ftSequence(3) S1
    cross join (
        select
            avg(rand(checksum(newid()))) R1,
            avg(rand(checksum(newid())) + 0) R2
        from ftSequence(3)
    ) R

そして次の結果を得ました:

R1                     R2
---------------------- ----------------------
0,6464                 0,4501
0,6464                 0,4501
0,6464                 0,4501

この時点で、正しい結果なのか、それとも値がすべてランダムであるべきなのか、自分で答えることができませんでした。すべての値をランダムにする方法は何ですか?

4

1 に答える 1

1

質問で述べたように、ランダムなテストデータのセットが必要でしrand()たが、どれが均一に分布しているかではなく、

select avg(rand(checksum(newid()))) from ftSequence(@n)

ガウス分布に収束します。

代わりに、外側のスコープデータの無意味なチェックを追加してステートメントをcross join使用できることがわかりました。cross apply

declare @rCnt int, @n int
set @rCnt = 5000000
set @n = 5

select R.*
from ftSequence(@rCnt) S
    cross apply (
        select
            avg(rand(checksum(newid())) + 1e-101) R1,
            avg(rand(checksum(newid())) + 1e-102) R2,
            avg(rand(checksum(newid())) + 1e-103) R3
        from ftSequence(@n)
        where S.N is not NULL
    ) R

ただし、信頼できるアプローチと見なすことができるかどうかはわかりません。

以下は、より信頼できる代替手段になる可能性があります。

declare @rCnt int, @n int
set @rCnt = 5000000
set @n = 5

create table #Rand (ValNo int, R1 float, R2 float, R3 float)
create clustered index #IX_Rand on #Rand (ValNo)

insert into #Rand
select
    S.N / @n,
    rand(checksum(newid())) R1,
    rand(checksum(newid())) R2,
    rand(checksum(newid())) R3
from ftSequence(@n * @rCnt) S

select AVG(R.R1), AVG(R.R2), AVG(R.R3)
from #Rand R
group by ValNo
于 2013-07-06T17:17:51.243 に答える