SQLで行をランダムに選択する方法は?


226

私はMSSQL Server 2005を使用しています。私のデータベースには、「customerNames」というテーブルがあり、「Id」と「Name」の2つの列があり、約 1,000件。

毎回ランダムに5人の顧客を選択する必要がある機能を作成しています。クエリが実行されるたびにランダムな5行(Id、およびName)を取得するクエリを作成する方法を誰かに教えてもらえますか?


ランダムはデータベースの一般的な要件ではありません。SQLのリンクを見つけて驚いた
Paxic 2009

2
どの程度のランダム性が必要かによって異なります。NEW_IDとRAND()の比較については、msdn.microsoft.com / en
シャノン

回答:


639
SELECT TOP 5 Id, Name FROM customerNames
ORDER BY NEWID()

とはいえ、皆さんの質問に対するより一般的な答えを求めて、誰もがこのページにアクセスするようです。

SQLでランダムな行を選択する

MySQLでランダムな行を選択します。

SELECT column FROM table
ORDER BY RAND()
LIMIT 1

PostgreSQLでランダムな行を選択します。

SELECT column FROM table
ORDER BY RANDOM()
LIMIT 1

Microsoft SQL Serverでランダムな行を選択します。

SELECT TOP 1 column FROM table
ORDER BY NEWID()

IBM DB2でランダムな行を選択する

SELECT column, RAND() as IDX 
FROM table 
ORDER BY IDX FETCH FIRST 1 ROWS ONLY

Oracleでランダムなレコードを選択します。

SELECT column FROM
( SELECT column FROM table
ORDER BY dbms_random.value )
WHERE rownum = 1

sqliteでランダムな行を選択します。

SELECT column FROM table 
ORDER BY RANDOM() LIMIT 1

3
+1は、将来のユーザーがこの質問を見たときにダウンする可能性のある外部サイト(承認された回答など)にリンクするのではなく、SOに直接回答を投稿します。
Ray Zhou

17
これは、各行が乱数を取得し、インデックス付けされていない大きな乱数セットがソートされる大きなテーブルでは非常に高価になりますか?
Andrey

これはほとんどの人におそらく明らかであるが、それは私には明らかではなかった...次のクエリでは、各行のための新しいランダムな値を得ることはありません: update tbl_vouchers set tbl_UsersID = (select top(1) id from tbl_Users order by NEWID()) -編集:私はコメントで仕事にフォーマットを取得することはできません:(
ミール

あなたは天才です!サブクエリと行番号を含むめちゃくちゃ長いクエリを行って書くまで、私はこれを見ていないので、私はあなたをとても嫌っています。
greenkode

5
警告:大きなデータベースの場合、この方法ではパフォーマンスが低下します。データベースに100万のエントリがある場合、各行のランダムな値を生成するのにかかる時間を想像できますか?あなたはここでより多くの情報とより良い代替案を持つことができます
Francis Ngueukam 16



9

多分このサイトは助けになるでしょう。

クリックスルーしたくない人のために:

SELECT TOP 1 column FROM table
ORDER BY NEWID()

2
少なくとも1を5に置き換える必要があります:)
roman m


5

数百万行のテーブルがあり、パフォーマンスを気にしている場合、これはより良い答えになるでしょう。

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

https://msdn.microsoft.com/en-us/library/cc441928.aspx


これにより、テーブルの行の約10%が選択されることに注意してください。正確な数の行、または少なくともN行を選択する必要がある場合、このアプローチは機能しません。
LarsH

4

これは古い質問ですが、新しいフィールド(NEWID()またはORDER BY rand()のいずれか)を多数の行があるテーブルに適用しようとすると、法外なコストがかかります。インクリメンタルな一意のIDがある場合(およびホールがない場合)、GUIDなどをすべての行に適用してから上位X#を取得する代わりに、選択するIDのX#を計算する方が効率的です。

DECLARE @minValue int;
DECLARE @maxValue int;
SELECT @minValue = min(id), @maxValue = max(id) from [TABLE];

DECLARE @randomId1 int, @randomId2 int, @randomId3 int, @randomId4 int, @randomId5 int
SET @randomId1 = ((@maxValue + 1) - @minValue) * Rand() + @minValue
SET @randomId2 = ((@maxValue + 1) - @minValue) * Rand() + @minValue
SET @randomId3 = ((@maxValue + 1) - @minValue) * Rand() + @minValue
SET @randomId4 = ((@maxValue + 1) - @minValue) * Rand() + @minValue
SET @randomId5 = ((@maxValue + 1) - @minValue) * Rand() + @minValue

--select @maxValue as MaxValue, @minValue as MinValue
--  , @randomId1 as SelectedId1
--  , @randomId2 as SelectedId2
--  , @randomId3 as SelectedId3
--  , @randomId4 as SelectedId4
--  , @randomId5 as SelectedId5

select * from [TABLE] el
where el.id in (@randomId1, @randomId2, @randomId3, @randomId4, @randomId5)

さらに多くの行を選択したい場合は、#tempTableにIDと一連のrand()値を設定してから、各rand()値を使用してmin-max値にスケーリングします。そうすれば、@ randomId1 ... nパラメータをすべて定義する必要がなくなります。以下の例には、CTEを使用して初期テーブルにデータを入力します。

DECLARE @NumItems int = 100;

DECLARE @minValue int;
DECLARE @maxValue int;
SELECT @minValue = min(id), @maxValue = max(id) from [TABLE];
DECLARE @range int = @maxValue+1 - @minValue;

with cte (n) as (
   select 1 union all
   select n+1 from cte
   where n < @NumItems
)
select cast( @range * rand(cast(newid() as varbinary(100))) + @minValue as int) tp
into #Nt
from cte;

select * from #Nt ntt
inner join [TABLE] i on i.id = ntt.tp;

drop table #Nt;

@Protiguous、あなたが提案した編集はランダムな選択を壊しました。65556.> PK IDで行を選択することをユーザに許可しないであろうdbo.Tally64kテーブルに適用分()とmax()を使用して
RIanGillis

テーブル名の変更は、単にテストの成果物でした。正しいテーブルが使用されている限り、実際のテーブル名は重要ではありません。min()とmax()は、2つではなく1つのクエリでクエリできます。これは、私が表示しようとしていたものです。
隣接する

@Protiguousああ、わかりました。今は、min-maxを実行するときに0-65kを使用したが、後で実行していないため、混乱しました。最新の編集後、実際に行った変更のパフォーマンスへの影響についてお聞きしたいと思います。パフォーマンスチューニングは私の興味の1つであり、等号のどちら側に配置するかなど、意味がないように見える決定は実際に大きな影響を与える可能性があるためです。 -同じことが5つのSET @ randomId ##呼び出しに適用されますか?それとも実際のテーブルからSELECTしていないので違いますか?
RIanGillis

私はあなたの質問を理解しているのかわかりません。なぜSELECTが1つではなく5つのSET @ id1 = rand()、@ id2 = rand()..になっているのかと尋ねていますか?これは、1つのステートメントでrand()を複数回呼び出しても同じ結果が生成されるため、SETが分離されるためです。(SQL Serverのrand()は決定論的な関数だと思います。)私は、1つの選択と5つのセットがパフォーマンス面でナノ秒の範囲にあると思います。
隣接する

4
SELECT * FROM TABLENAME ORDER BY random() LIMIT 5; 

古い質問ですが、この答えはOracleではうまくいきませんでした。
クマ

SELECT * FROM(SELECT * FROM table ORDER BY DBMS_RANDOM.VALUE)WHERE rownum <number; @Bear試してみる
Narendra

3

これはビッグデータに最適です。

SELECT TOP 1 Column_Name FROM dbo.Table TABLESAMPLE(1 PERCENT);

TABLESAMPLE(n ROWS) or TABLESAMPLE(n PERCENT) ランダムですが、追加する必要があります TOP n、正しいサンプルサイズを取得ます。

NEWID()大きなテーブルでは、使用に非常に時間がかかります。


0

この記事で説明したように、SQL結果セットをシャッフルするには、データベース固有の関数呼び出しを使用する必要があります。

RANDOM関数を使用して大きな結果セットをソートすると、処理が非常に遅くなる場合があることに注意してください。そのため、小さな結果セットでそれを実行してください。

あなたが大きな結果セットをシャッフルし、その後、それを制限する必要がある場合、それはよりよく利用するようなものだオラクルSAMPLE(N)またはTABLESAMPLESQL Serverのか、PostgreSQLの ORDER BY句で代わりにランダム関数の。

したがって、次のデータベーステーブルがあるとします。

ここに画像の説明を入力してください

そして、以下の行 songテーブルの:

| id | artist                          | title                              |
|----|---------------------------------|------------------------------------|
| 1  | Miyagi & Эндшпиль ft. Рем Дигга | I Got Love                         |
| 2  | HAIM                            | Don't Save Me (Cyril Hahn Remix)   |
| 3  | 2Pac ft. DMX                    | Rise Of A Champion (GalilHD Remix) |
| 4  | Ed Sheeran & Passenger          | No Diggity (Kygo Remix)            |
| 5  | JP Cooper ft. Mali-Koa          | All This Love                      |

オラクル

Oracleでは、 DBMS_RANDOM.VALUE、次の例に示すように関数。

SELECT
    artist||' - '||title AS song
FROM song
ORDER BY DBMS_RANDOM.VALUE

前述のSQLクエリをOracleで実行すると、次の結果セットが得られます。

| song                                              |
|---------------------------------------------------|
| JP Cooper ft. Mali-Koa - All This Love            |
| 2Pac ft. DMX - Rise Of A Champion (GalilHD Remix) |
| HAIM - Don't Save Me (Cyril Hahn Remix)           |
| Ed Sheeran & Passenger - No Diggity (Kygo Remix)  |
| Miyagi & Эндшпиль ft. Рем Дигга - I Got Love      |

のおかげで、曲がランダムな順序でリストされていることに注意してください DBMS_RANDOM.VALUEORDER BY句で使用される関数呼び出しの。

SQLサーバー

SQL ServerではNEWID、次の例に示すように、関数を使用する必要があります。

SELECT
    CONCAT(CONCAT(artist, ' - '), title) AS song
FROM song
ORDER BY NEWID()

前述のSQLクエリをSQL Serverで実行すると、次の結果セットが取得されます。

| song                                              |
|---------------------------------------------------|
| Miyagi & Эндшпиль ft. Рем Дигга - I Got Love      |
| JP Cooper ft. Mali-Koa - All This Love            |
| HAIM - Don't Save Me (Cyril Hahn Remix)           |
| Ed Sheeran & Passenger - No Diggity (Kygo Remix)  |
| 2Pac ft. DMX - Rise Of A Champion (GalilHD Remix) |

NEWIDORDER BY句で使用される関数呼び出しのおかげで、曲がランダムな順序でリストされていることに注意してください。

PostgreSQL

PostgreSQLではrandom、次の例に示すように、関数を使用する必要があります。

SELECT
    artist||' - '||title AS song
FROM song
ORDER BY random()

前述のSQLクエリをPostgreSQLで実行すると、次の結果セットが取得されます。

| song                                              |
|---------------------------------------------------|
| 2Pac ft. DMX - Rise Of A Champion (GalilHD Remix) |
| JP Cooper ft. Mali-Koa - All This Love            |
| Ed Sheeran & Passenger - No Diggity (Kygo Remix)  |
| HAIM - Don't Save Me (Cyril Hahn Remix)           |
| Miyagi & Эндшпиль ft. Рем Дигга - I Got Love      |

randomORDER BY句で使用される関数呼び出しのおかげで、曲がランダムな順序でリストされていることに注意してください。

MySQL

MySQLではRAND、次の例に示すように、関数を使用する必要があります。

SELECT
  CONCAT(CONCAT(artist, ' - '), title) AS song
FROM song
ORDER BY RAND()

MySQLで前述のSQLクエリを実行すると、次の結果セットが取得されます。

| song                                              |
|---------------------------------------------------|
| HAIM - Don't Save Me (Cyril Hahn Remix)           |
| Ed Sheeran & Passenger - No Diggity (Kygo Remix)  |
| Miyagi & Эндшпиль ft. Рем Дигга - I Got Love      |
| 2Pac ft. DMX - Rise Of A Champion (GalilHD Remix) |
| JP Cooper ft. Mali-Koa - All This Love            |

RANDORDER BY句で使用される関数呼び出しのおかげで、曲がランダムな順序でリストされていることに注意してください。


0

大きなテーブルを使用していて、データの10%にアクセスしたい場合は、次のコマンドを実行します。 SELECT TOP 10 PERCENT * FROM Table1 ORDER BY NEWID();

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.