如何在 SQL 中随机选择行?

Posted

技术标签:

【中文标题】如何在 SQL 中随机选择行?【英文标题】:How to randomly select rows in SQL? 【发布时间】:2010-10-09 12:01:07 【问题描述】:

我使用的是 MSSQL Server 2005。在我的数据库中,我有一个表“customerNames”,它有两列“Id”和“Name”,大约1,000 个结果。

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

【问题讨论】:

随机不是数据库的常见要求,我很惊讶地发现 link 用于某些 SQL 取决于你想要多少随机性。请参阅:msdn.microsoft.com/en-us/library/aa175776(SQL.80).aspx 以比较 NEW_ID 与 RAND() 【参考方案1】:

也许this site 会有所帮助。

对于那些不想点击的人:

SELECT TOP 1 column FROM table
ORDER BY NEWID()

【讨论】:

应该至少将 1 替换为 5 :)【参考方案2】:
SELECT TOP 5 Id, Name FROM customerNames ORDER BY NEWID()

【讨论】:

【参考方案3】:

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

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

【讨论】:

【参考方案4】:
SELECT TOP 5 Id, Name FROM customerNames
ORDER BY NEWID()

也就是说,似乎每个人都来到这个页面是为了更一般地回答你的问题:

Selecting a random row in 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

【讨论】:

+1 用于直接在 SO 上发布答案,而不是链接到外部网站(如已接受的答案),当未来用户查看此问题时,该网站可能会关闭。 这在大表上是否会变得非常昂贵,每行获取一个随机数,然后对一个大的未索引随机数集进行排序? 这对大多数人来说可能很明显,但对我来说并不明显......以下查询不会为每一行获取新的随机值:update tbl_vouchers set tbl_UsersID = (select top(1) id from tbl_Users order by NEWID()) - 编辑:我可以' t 让格式在 cmets 中起作用 :( 为什么这在 Google Cloud SQL 上会失败?我们只能得到部分随机的结果。将近 80% 的时间我们会返回同一行。 警告:对于大型数据库,此方法性能不佳。如果数据库有一百万个条目,你能想象为每一行生成一个随机值所需的时间吗?您可以了解更多信息和更好的替代方案here。【参考方案5】:

这里有一个很好的 Microsoft SQL Server 2005 特定解决方案。 处理您处理大型结果集的问题(不是我知道的问题)。

从大表中随机选择行 http://msdn.microsoft.com/en-us/library/cc441928.aspx

【讨论】:

【参考方案6】:

我发现这最适合大数据。

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

TABLESAMPLE(n ROWS) or TABLESAMPLE(n PERCENT) 是随机的,但需要添加TOP n 才能获得正确的样本量。

在大表上使用NEWID() 非常慢。

【讨论】:

【参考方案7】:
SELECT * FROM TABLENAME ORDER BY random() LIMIT 5; 

【讨论】:

SELECT * FROM (SELECT * FROM table ORDER BY DBMS_RANDOM.VALUE) WHERE rownum 【参考方案8】:

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

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 行,这种方法将不起作用。【参考方案9】:

这是一个老问题,但尝试将新字段(NEWID() 或 ORDER BY rand())应用于具有大量行的表会非常昂贵。如果您有增量的唯一 ID(并且没有任何漏洞),那么计算要选择的 X # 个 ID 而不是对每一行应用 GUID 或类似然后取前 X # 个 ID 会更有效。

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 表的 min() 和 max() 将不允许用户选择 pk id > 65556 的行。 表名更改只是测试的产物。只要使用正确的表,实际的表名并不重要。 min() 和 max() 都可以在一个查询中查询,而不是两个,这就是我想要展示的。 @Protiguous 啊,我现在明白了,我很困惑,因为你在做 min-max 时使用了 0-65k,但后来没有。在您最近的编辑之后,我实际上想问您所做的更改对性能的影响,因为性能调整是我的兴趣之一,并且看似毫无意义的决定,例如您在等号的哪一侧放置某些东西实际上可能会产生重大影响 - -- 同样的事情是否适用于 5 SET @randomId## 调用?还是因为它不是从实际表中选择而有所不同? 我不确定我是否理解您的问题。你在问为什么有 5 个 SET 而不是只有 1 个 SELECT @id1=rand(), @id2=rand().. ?这是因为在 1 条语句中多次调用 rand() 将产生相同的结果,因此是分离的 SET。 (我相信,SQL Server 上的 rand() 是一个确定性函数。)我猜测 1 select vs 5 set 在性能方面处于纳秒范围内。【参考方案10】:

为了打乱 SQL 结果集,您需要使用特定于数据库的函数调用。

请注意,使用 RANDOM 函数对大型结果集进行排序可能会非常慢,因此请确保对小型结果集进行排序。

如果您必须对大型结果集进行洗牌并在之后对其进行限制,那么最好在SQL Server 或PostgreSQL 中使用Oracle SAMPLE(N)TABLESAMPLE 之类的东西,而不是在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      |

请注意,由于 ORDER BY 子句使用了DBMS_RANDOM.VALUE 函数调用,歌曲是按随机顺序列出的。

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

请注意,由于 ORDER BY 子句使用了 NEWID 函数调用,歌曲是按随机顺序列出的。

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      |

请注意,由于 ORDER BY 子句使用了random 函数调用,歌曲是按随机顺序列出的。

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            |

请注意,由于 ORDER BY 子句使用了 RAND 函数调用,歌曲是按随机顺序列出的。

【讨论】:

【参考方案11】:

如果您使用的是大型表并希望访问 10% 的数据,请运行以下命令:SELECT TOP 10 PERCENT * FROM Table1 ORDER BY NEWID();

【讨论】:

【参考方案12】:

如果你使用 Yandex 数据库,那么你应该使用

select column from table order by random (TableRow()) limit 1;

【讨论】:

以上是关于如何在 SQL 中随机选择行?的主要内容,如果未能解决你的问题,请参考以下文章

从表中随机选择行 - Python Pandas 读取 SQL

从表中随机选择行 - Python Pandas Read SQL

随机抽样的 SQL 分区

如何在 JPQL 中选择随机 10 条记录?

在 SQL Server 中,如何选择前 4 行?

为 SQL 连接选择单个(随机)行