SQLサーバーテーブルからランダムレコードを取得する簡潔な方法はありますか?
ユニットテストデータをランダム化したいので、テーブルからランダムIDを選択する簡単な方法を探しています。英語では、selectは「テーブルから1つのIDを選択します。このIDは、テーブル内の最小IDとテーブル内の最大IDの間の乱数です。」
クエリを実行し、null値をテストしてから、nullの場合は再実行する必要がないので、それを実行する方法を見つけることはできません。
アイデア?
SQLサーバーテーブルからランダムレコードを取得する簡潔な方法はありますか?
ユニットテストデータをランダム化したいので、テーブルからランダムIDを選択する簡単な方法を探しています。英語では、selectは「テーブルから1つのIDを選択します。このIDは、テーブル内の最小IDとテーブル内の最大IDの間の乱数です。」
クエリを実行し、null値をテストしてから、nullの場合は再実行する必要がないので、それを実行する方法を見つけることはできません。
アイデア?
回答:
SQLサーバーテーブルからランダムレコードを取得する簡潔な方法はありますか?
はい
SELECT TOP 1 * FROM table ORDER BY NEWID()
NEWID()
行ごとにAが生成され、テーブルはそれによってソートされます。最初のレコードが返されます(つまり、「最も低い」GUIDを持つレコード)。
バージョン4以降、GUIDは疑似乱数として生成されます。
バージョン4のUUIDは、真の乱数または疑似乱数からUUIDを生成するためのものです。
アルゴリズムは次のとおりです。
- clock_seq_hi_and_reservedの最上位2ビット(ビット6と7)をそれぞれ0と1に設定します。
- time_hi_and_versionフィールドの最上位4ビット(ビット12から15)をセクション4.1.3の4ビットバージョン番号に設定します。
- 他のすべてのビットをランダムに(または疑似ランダムに)選択された値に設定します。
代替案SELECT TOP 1 * FROM table ORDER BY RAND()
は、人が考えるようには機能しません。RAND()
クエリごとに1つの値を返すため、すべての行が同じ値を共有します。
GUID値は疑似ランダムですが、より要求の厳しいアプリケーションには、より優れたPRNGが必要になります。
通常のパフォーマンスは、約1,000,000行で10秒未満です。もちろん、システムによって異なります。インデックスをヒットすることは不可能であるため、パフォーマンスが比較的制限されることに注意してください。
TOP 1
、同じページの行が相関しているかどうかは関係ありません。あなたはそれらのうちの1つだけを選んでいます。
また、メソッドを試して、MIN(Id)とMAX(Id)の間のランダムなIDを取得してから、
SELECT TOP 1 * FROM table WHERE Id >= @yourrandomid
常に1行になります。
大きなデータを選択したい場合、私が知っている最善の方法は次のとおりです。
SELECT * FROM Table1
WHERE (ABS(CAST(
(BINARY_CHECKSUM
(keycol1, NEWID())) as int))
% 100) < 10
出典:MSDN
私は自分が試した方法を改善しようとしていて、この投稿に出くわしました。古いことに気づきましたが、この方法は記載されていません。テストデータを作成して適用しています。これは、@ st(2文字の状態)で呼び出されたSPの「アドレス」のメソッドを示しています。
Create Table ##TmpAddress (id Int Identity(1,1), street VarChar(50), city VarChar(50), st VarChar(2), zip VarChar(5))
Insert Into ##TmpAddress(street, city, st, zip)
Select street, city, st, zip
From tbl_Address (NOLOCK)
Where st = @st
-- unseeded RAND() will return the same number when called in rapid succession so
-- here, I seed it with a guaranteed different number each time. @@ROWCOUNT is the count from the most recent table operation.
Set @csr = Ceiling(RAND(convert(varbinary, newid())) * @@ROWCOUNT)
Select street, city, st, Right(('00000' + ltrim(zip)),5) As zip
From ##tmpAddress (NOLOCK)
Where id = @csr
個々の行のランダムサンプルが本当に必要な場合は、TABLESAMPLEを使用する代わりに、クエリを変更して行をランダムに除外します。たとえば、次のクエリはNEWID関数を使用して、Sales.SalesOrderDetailテーブルの行の約1パーセントを返します。
SELECT * FROM Sales.SalesOrderDetail
WHERE 0.01 >= CAST(CHECKSUM(NEWID(), SalesOrderID) & 0x7fffffff AS float)
/ CAST (0x7fffffff AS int)
SalesOrderID列はCHECKSUM式に含まれているため、NEWID()は行ごとに1回評価して、行ごとにサンプリングを実行します。式CAST(CHECKSUM(NEWID()、SalesOrderID)&0x7fffffff AS float / CAST(0x7fffffff AS int)は、0から1までのランダムなfloat値に評価されます。」
ソース:http://technet.microsoft.com/en-us/library/ms189108(v = sql.105).aspx
これについては、以下でさらに説明します。
これはどのように作動しますか?WHERE句を分割して説明しましょう。
CHECKSUM関数は、リスト内の項目のチェックサムを計算しています。NEWID()は新しいランダムGUIDを返す関数であるため、SalesOrderIDが必要かどうかについては議論の余地があります。したがって、ランダムな数値に定数を掛けると、いずれの場合もランダムになります。実際、SalesOrderIDを除外しても違いはないようです。あなたが熱心な統計学者であり、これを含めることを正当化できる場合は、以下のコメントセクションを使用して、私が間違っている理由を教えてください!
CHECKSUM関数はVARBINARYを返します。バイナリの(111111111 ...)に相当する0x7fffffffを使用してビット単位のAND演算を実行すると、0と1のランダムな文字列を効果的に表す10進値が生成されます。係数0x7fffffffで除算すると、この10進数が0〜1の数値に効果的に正規化されます。次に、各行が最終結果セットに含める価値があるかどうかを判断するために、1 / xのしきい値(この場合は0.01)が使用されます。 xは、サンプルとして取得するデータのパーセンテージです。
ソース:https://www.mssqltips.com/sqlservertip/3157/different-ways-to-get-random-data-for-sql-server-data-sampling