如何在SQL中随机选择行?


226

我正在使用MSSQL Server2005。在我的数据库中,我有一个表“ customerNames”,其中有两列“ Id”和“ Name”以及大约。1,000个结果。

我正在创建一个功能,每次必须随机选择5个客户。谁能告诉我如何创建一个查询,该查询每次执行查询时都会随机获得5行(Id和Name)?


随机不是数据库的常见要求,我很惊讶地找到一些SQL 的链接
Paxic'Feb

2
取决于您想要多少随机性。有关NEW_ID与RAND()的比较,请参阅:msdn.microsoft.com/zh-cn/library/aa175776 (SQL.80).aspx
Shannon Severance 2009年

Answers:


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 2014年

这对大多数人来说也许是显而易见的,但对我而言却不是显而易见的...以下查询将不会为每一行获取新的随机值: update tbl_vouchers set tbl_UsersID = (select top(1) id from tbl_Users order by NEWID()) -编辑:我无法在注释中使用格式:(
Mir

天才!我非常讨厌您,因为直到我离开并用子查询和行号编写了一个疯狂的长查询,我才看到它。
greenkode '16

5
警告:对于大型数据库,此方法将具有较差的性能。您是否可以想象如果数据库具有一百万个条目,那么为每一行生成一个随机值将花费多少时间?您可以在此处了解更多信息和更好的替代方法。
弗朗西斯·恩格卡姆


11

如果有人想要PostgreSQL解决方案:

select id, name
from customer
order by random()
limit 5;

这个答案对PostgreSQL有好处,不需要限制。
aliasbody

9

也许这个站点会有所帮助。

对于那些不想点击的人:

SELECT TOP 1 column FROM table
ORDER BY NEWID()

2
应该至少用5代替1 :)
罗马m


5

如果您有一个包含数百万行的表并关心性能,那么这可能是一个更好的答案:

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

https://msdn.microsoft.com/zh-CN/library/cc441928.aspx


请注意,这将选择表中大约10%的行。如果您需要选择确切的行数,或者至少选择N行,则此方法将行不通。
LarsH

4

这是一个古老的问题,但是尝试将新字段(NEWID()或ORDER BY rand())应用于具有大量行的表将非常昂贵。如果您具有递增的唯一ID(并且没有任何漏洞),则计算要选择的X#ID而不是对每行应用GUID或类似的代码,然后取前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)

如果要选择更多行,我将研究使用ID和一堆rand()值填充#tempTable,然后使用每个rand()值缩放到最小-最大值。这样,您不必定义所有@ 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,您建议的编辑破坏了随机选择。使用施加到dbo.Tally64k表分钟()和max()将不允许用户选择与一个PK ID的行> 65556.
RIanGillis

更改表名只是测试中的产物。只要使用正确的表,实际的表名就没有关系。min()和max()都可以在一个查询中查询,而不是两个,这就是我试图显示的内容。
毗邻的

@Protiguous啊,我现在看到了,我很困惑,因为您在进行min-max时使用了0-65k,但后来没有使用。在您进行了最近的编辑后,我实际上想向您询问所做更改对性能的影响,因为性能调整是我的兴趣之一,而且看起来无意义的决定(例如,在等号的哪一侧放东西)实际上可能会产生重大影响- -同样的事情适用于5个SET @ randomId ##调用吗?还是因为它不是从实际表中进行选择而不同?
RIanGillis

我不确定我是否理解您的问题。您是否在问为什么有5个SET而不是仅1个SELECT @ id1 = rand(),@ id2 = rand()..?这是因为在1条语句中多次调用rand()会产生相同的结果,因此将SET分开。(我相信,SQL Server上的rand()是确定性函数。)我猜想 1 select vs 5 set在性能方面处于纳秒范围内。
邻近

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

旧问题,但是这个答案在Oracle中没有为我解决。

SELECT * FROM(SELECT * FROM table ORDER BY DBMS_RANDOM.VALUE)WHERE rownum <数字;@熊试试这个
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函数对大型结果集进行排序可能会非常缓慢,因此请确保对小型结果集执行此操作。

如果必须改组较大的结果集并在之后对其进行限制,那么最好使用OracleSAMPLE(N)SQL ServerPostgreSQL中TABLESAMPLEin 而不是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

在Oracle上运行上述SQL查询时,我们将获得以下结果集:

| 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 Server上运行上述SQL查询时,我们将获得以下结果集:

| 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()

在PostgreSQL上运行上述SQL查询时,我们将获得以下结果集:

| 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();

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.