如何在 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