web-dev-qa-db-ja.com

データベーステーブルからのランダムレコード(T-SQL)

SQLサーバーのテーブルからランダムなレコードを取得する簡単な方法はありますか?

ユニットテストデータをランダム化したいので、テーブルからランダムIDを選択する簡単な方法を探しています。英語での選択は、「テーブルからIDを1つ選択します。IDは、テーブル内の最小IDとテーブル内の最大IDの間の乱数です」。

クエリを実行し、null値をテストし、nullの場合は再実行する必要なしに、それを行う方法がわかりません。

アイデア?

80
Jeremy

SQLサーバーのテーブルからランダムなレコードを取得する簡単な方法はありますか?

はい

_SELECT TOP 1 * FROM table ORDER BY NEWID()
_

説明

NEWID()が各行に対して生成され、テーブルはそれによってソートされます。最初のレコードが返されます(つまり、「最も低い」GUIDを持つレコード)。

ノート

  1. GUIDは、バージョン4以降の擬似乱数として生成されます。

    バージョン4 UUIDは、真の乱数または擬似乱数からUUIDを生成するためのものです。

    アルゴリズムは次のとおりです。

    • Clock_seq_hi_and_reservedの2つの最上位ビット(ビット6および7)をそれぞれ0および1に設定します。
    • Time_hi_and_versionフィールドの最上位4ビット(ビット12〜15)をセクション4.1.3の4ビットバージョン番号に設定します。
    • 他のすべてのビットをランダムに(または擬似ランダムに)選択した値に設定します。

    ユニバーサル一意識別子(UUID)URN名前空間-RFC 4122

  2. 代替のSELECT TOP 1 * FROM table ORDER BY Rand()は、考えられるようには機能しません。 Rand()はクエリごとに1つの値を返すため、すべての行が同じ値を共有します。

  3. GUID=値は擬似ランダムですが、より要求の厳しいアプリケーションには、より良いPRNGが必要です。

  4. 通常、システムによって異なりますが、通常は約1,000,000行で10秒未満のパフォーマンスです。インデックスにヒットすることは不可能であるため、パフォーマンスは比較的制限されることに注意してください。

135
Sklivvz

大きなテーブルでは、TABLESAMPLEを使用してテーブル全体をスキャンしないようにすることもできます。

SELECT  TOP 1 *
FROM YourTable
TABLESAMPLE (1000 ROWS)
ORDER BY NEWID()

ORDER BY NEWIDは、データページで最初に表示される行を返すことを避けるために必要です。

使用する数値は、テーブルのサイズと定義のために慎重に選択する必要があり、行が返されない場合は再試行ロジックを検討できます。この背後にある数学と、この手法が小さなテーブルに適さない理由は、 ここで説明

23
Martin Smith

また、メソッドを試してMIN(Id)とMAX(Id)の間のランダムIDを取得してから、

SELECT TOP 1 * FROM table WHERE Id >= @yourrandomid

常に1行になります。

8
Sklivvz

大きなデータを選択する場合、私が知っている最良の方法は次のとおりです。

SELECT * FROM Table1
WHERE (ABS(CAST(
    (BINARY_CHECKSUM
    (keycol1, NEWID())) as int))
    % 100) < 10

ソース: [〜#〜] msdn [〜#〜]

7
hmfarimani

私が試した方法を改善したいと考えていたので、この投稿に出くわしました。古いことはわかっていますが、この方法はリストされていません。テストデータを作成および適用しています。これは、SP @st(2文字の状態)で呼び出された場合の「アドレス」のメソッドを示しています

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
0
user2788934