14

ページングなどの目的で、結果を繰り返し可能な方法でランダムに並べ替えたいと思います。このNEWID()は、同じ結果を再取得できないという点でランダムすぎます。同じシードを使用すると同じランダムコレクションが生成されるため、Rand(シード)による順序付けが理想的です。残念ながら、Rand()の状態は行ごとにリセットされますが、解決策はありますか?

declare @seed as int;
set @seed = 1000;

create table temp (
id int,
date datetime)

insert into temp (id, date) values (1,'20090119')
insert into temp (id, date) values (2,'20090118')
insert into temp (id, date) values (3,'20090117')
insert into temp (id, date) values (4,'20090116')
insert into temp (id, date) values (5,'20090115')
insert into temp (id, date) values (6,'20090114')

-- re-seeds for every item
select *, RAND(), RAND(id+@seed) as r from temp order by r
--1 2009-01-19 00:00:00.000 0.277720118060575   0.732224964471124
--2 2009-01-18 00:00:00.000 0.277720118060575   0.732243597442382
--3 2009-01-17 00:00:00.000 0.277720118060575   0.73226223041364
--4 2009-01-16 00:00:00.000 0.277720118060575   0.732280863384898
--5 2009-01-15 00:00:00.000 0.277720118060575   0.732299496356156
--6 2009-01-14 00:00:00.000 0.277720118060575   0.732318129327415
-- Note how the last column is +=~0.00002

drop table temp

-- interestingly this works:
select RAND(@seed), RAND()
--0.732206331499865 0.306382810665955

注:Rand(ID)を試しましたが、ソートされていることがわかりました。どうやらRand(n)<Rand(n + 1)

4

7 に答える 7

15

gkrogersハッシュ提案から構築すると、これはうまく機能します。パフォーマンスについて何か考えはありますか?

declare @seed as int;
set @seed = 10;

create table temp (
id int,
date datetime)

insert into temp (id, date) values (1,'20090119')
insert into temp (id, date) values (2,'20090118')
insert into temp (id, date) values (3,'20090117')
insert into temp (id, date) values (4,'20090116')
insert into temp (id, date) values (5,'20090115')
insert into temp (id, date) values (6,'20090114')

-- re-seeds for every item
select *, HASHBYTES('md5',cast(id+@seed as varchar)) r
from temp order by r
--1 2009-01-19 00:00:00.000 0x6512BD43D9CAA6E02C990B0A82652DCA
--5 2009-01-15 00:00:00.000 0x9BF31C7FF062936A96D3C8BD1F8F2FF3
--4 2009-01-16 00:00:00.000 0xAAB3238922BCC25A6F606EB525FFDC56
--2 2009-01-18 00:00:00.000 0xC20AD4D76FE97759AA27A0C99BFF6710
--3 2009-01-17 00:00:00.000 0xC51CE410C124A10E0DB5E4B97FC2AF39
--6 2009-01-14 00:00:00.000 0xC74D97B01EAE257E44AA9D5BADE97BAF

drop table temp

編集:クエリで使用される@seedの宣言は、動的SQLが使用されている場合は、パラメーターまたは定数intに置き換えることができることに注意してください。(TSQL形式での@intの宣言は必要ありません)

于 2009-01-19T16:42:15.227 に答える
1
SELECT *, checksum(id) AS r FROM table ORDER BY r

このような作品。checksum()からの出力は、私にはそれほどランダムに見えませんが。MSDNドキュメントには次のように記載されています。

[...]、アプリケーションが時々変更を見逃すことを許容できない限り、チェックサムを使用して値が変更されたかどうかを検出することはお勧めしません。代わりにHashBytesの使用を検討してください。MD5ハッシュアルゴリズムが指定されている場合、HashBytesが2つの異なる入力に対して同じ結果を返す確率は、CHECKSUMの確率よりもはるかに低くなります。

しかし、それはもっと速いかもしれません。

于 2009-01-30T15:36:19.427 に答える
1

各行の値を使用して、rand関数を再評価できます。

Select *, Rand(@seed + id) as r from temp order by r

IDを追加すると、行ごとにランドが再シードされます。ただし、シードの値については、常に同じ行のシーケンスが返されます(テーブルが変更されない場合)。

于 2009-01-19T16:28:55.503 に答える
1

ハッシュの作成は、シードされた乱数の作成よりもはるかに時間がかかる場合があります。

RAND([seed]) の ourput のバリエーションを増やすには、[seed] も大きく変化させる必要があります。もしかして…など

SELECT
    *,
    RAND(id * 9999)    AS [r]
FROM
   temp
ORDER BY
   r

定数を使用すると、要求した複製可能性が保証されます。ただし、(id * 9999) の結果、テーブルが十分に大きくなると予想される場合は、オーバーフローが発生することに注意してください...

于 2009-01-19T18:45:54.963 に答える
0

いくつか読んだ後、これは受け入れられた方法です。

Select Rand(@seed) -- now rand is seeded

Select *, 0 * id + Rand() as r from temp order by r

式にidを含めると、行ごとに再評価されます。ただし、0を掛けると、ランドの結果に影響を与えないことが保証されます。

なんて恐ろしいやり方でしょう。

于 2009-01-19T16:45:39.557 に答える
0
create table temp (
id int,
date datetime)

insert into temp (id, date) values (1,'20090119')
insert into temp (id, date) values (2,'20090118')
insert into temp (id, date) values (3,'20090117')
insert into temp (id, date) values (4,'20090116')
insert into temp (id, date) values (5,'20090115')
insert into temp (id, date) values (6,'20090114')

-- re-seeds for every item
select *, NEWID() r
from temp order by r

drop table temp
于 2009-09-24T23:17:02.083 に答える