当前位置: 首页
数据库
SQL分组随机抽取一条记录的方法

SQL分组随机抽取一条记录的方法

热心网友 时间:2026-07-16
转载

MySQL8 0+用ROW_NUMBER()OVER(PARTITIONBYcategoryORDERBYRAND())实现分组随机抽样;PostgreSQL用DISTINCTON+ORDERBYRANDOM();MySQL5 7需关联子查询加LIMIT1但性能差。应避免外层ORDERBYRAND()或GROUPBY聚合函数,无法得到真随机。

先抽个结论:在 MySQL 8.0 及以上版本里,用 ROW_NUMBER() OVER (PARTITION BY category ORDER BY RAND()) 做分组随机抽样,是最靠谱、语义最清晰的写法。它会先在每组内把记录顺序打乱,再编号,最后取每组 rn = 1 的那一行——干净利落,逻辑透明。

很多人容易踩的坑是:在最外层加个 ORDER BY RAND()。这其实只是把全表随机排序了一遍,然后分组——结果根本就不是“每组一条”,而是不可控的随机行数。还有人误用 GROUP BY 配合 MIN(id),本质是取最小 ID,跟随机八竿子打不着。

如何用SQL从分组中随机抽取一条记录?

MySQL 8.0+ 用 ROW_NUMBER() + RAND() 实现分组随机抽样

直接上正确写法,然后说几个关键点:

SELECT * FROM (  SELECT *,         ROW_NUMBER() OVER (PARTITION BY category ORDER BY RAND()) AS rn  FROM products) t WHERE rn = 1;
  • RAND() 必须放在窗口函数的 ORDER BY 里,而且不能加其他确定性排序字段。比如写成 ORDER BY category, RAND(),因为 category 是稳定的,同组内多次执行结果会一模一样,等于没随机。
  • 窗口函数只支持 MySQL 8.0+ 和 PostgreSQL;MariaDB 10.2+ 也支持,但旧版 MySQL(5.7 及之前)不行,得换方案。
  • 性能方面:全表扫描 + 每组内部排序,数据量大时会慢。如果只是偶尔跑一跑,或者数据在百万级以下,基本可以接受。

PostgreSQL 用 DISTINCT ON + ORDER BY RANDOM()

PostgreSQL 提供了一个更简洁的语法:DISTINCT ON 按指定列去重,配合 ORDER BY ... RANDOM() 控制保留哪一条。天生适合分组抽样,而且不需要子查询,清爽很多。

SELECT DISTINCT ON (category) *FROM productsORDER BY category, RANDOM();

这里有一个容易踩的坑:DISTINCT ON (category) 要求 ORDER BY 最左字段必须是 category,否则直接报错。另外 RANDOM() 必须出现在 ORDER BY 里,不能只靠 WHERE 过滤。

  • DISTINCT ON 返回的是“每组第一条”,所以 ORDER BY category, RANDOM() 才能保证每组内随机选一条。
  • 如果还想返回原表所有字段,category 必须放在 ORDER BY 开头,后面接 RANDOM(),其他字段顺序不影响结果。
  • 相比窗口函数,这个写法更轻量,执行计划通常更优,尤其在有 category 索引时。

MySQL 5.7 或 SQLite 等不支持窗口函数的场景

只能退回到“关联子查询 + LIMIT 1”模式。但注意:MySQL 5.7 不允许子查询里直接用 LIMIT 配合外部引用,必须包装成派生表;SQLite 则直接支持 LIMIT 写在子查询里。

性能差是最大问题——对主表每行都执行一次子查询,复杂度 O(n²)。数据超 1 万行就会明显卡顿。线上环境慎用,仅限临时查或小表。

  • MySQL 5.7 正确写法:子查询要用双层括号,比如 (SELECT * FROM (SELECT ... ORDER BY RAND() LIMIT 1) AS tmp)
  • SQLite 可以直接写 (SELECT * FROM products p2 WHERE p2.category = p1.category ORDER BY RANDOM() LIMIT 1)
  • 所有方案中,这是唯一可能重复返回同一行(虽然概率低),因为 RAND() 在子查询里每次独立生成,无法保证组内真正“只选一次”。
-- MySQL 5.7 示例(注意双层括号)SELECT p1.* FROM products p1WHERE p1.id = (  SELECT id FROM (    SELECT id FROM products p2    WHERE p2.category = p1.category    ORDER BY RAND() LIMIT 1  ) AS tmp);

为什么不能用 GROUP BY + AGGREGATE(比如 MAX(id)) 模拟随机?

因为 MAX(id)MIN(name) 这类聚合函数返回的是确定值,跟随机完全不沾边。有人试图用 GROUP_CONCAT(id ORDER BY RAND())SUBSTRING_INDEX 截取第一个,看似随机,实则隐患巨大:

  • GROUP_CONCAT 有长度限制(默认 1024 字符),超长组会截断,导致取不到真实 ID。
  • 字符串拼接后取子串,无法保证类型安全;如果 ID 是 UUID 或含逗号,解析直接失败。
  • MySQL 5.7 默认不开启 sql_mode=ONLY_FULL_GROUP_BY 时,SELECT * 配合 GROUP BY 会返回非确定性行,看起来像随机,其实是引擎随意选的,不可靠也不可移植。

真要兼容老版本,又不能接受性能损耗,优先考虑应用层分组后随机取——查出全部分组数据,用 Python/JS 在内存里按组 shuffle 再取首项,比写 SQL 黑魔法稳当得多。

来源:https://www.php.cn/faq/2823192.html

游乐网为非赢利性网站,所展示的游戏/软件/文章内容均来自于互联网或第三方用户上传分享,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系youleyoucom@outlook.com。

同类文章
更多
NET调用Oracle存储过程并处理多个输出游标的方法

NET调用Oracle存储过程并处理多个输出游标的方法

在 NET调用Oracle存储过程返回多个REFCURSOR时,需显式声明每个输出参数,设置Direction为Output、OracleDbType为RefCursor。调用后使用NextResult()按顺序切换游标并检查HasRows。连接字符串需启用Unicode=True和Pooling。建议手动读取避免DataSet Fill()的列名大小写问题

时间:2026-07-16 17:55
Oracle授予用户执行任意包过程权限的操作指南

Oracle授予用户执行任意包过程权限的操作指南

Oracle中EXECUTEANYPROCEDURE权限无法执行Package私有过程,仅对Spec公开子程序有效,需额外授权。正确做法是逐个授予GRANTEXECUTEON具体Package,避免越权与审计风险。

时间:2026-07-16 17:55
Oracle DG主备库DBID冲突导致连接失败的故障处理方法

Oracle DG主备库DBID冲突导致连接失败的故障处理方法

OracleDataGuard主备库连接失败非DBID冲突,常见原因为DB_UNIQUE_NAME重复、log_archive_config缺失或不一致,或备库未MOUNT。ORA-16047报错时,应先检查备库log_archive_config是否包含主库名。

时间:2026-07-16 17:54
Oracle 11g RMAN恢复三天前误删数据的方法

Oracle 11g RMAN恢复三天前误删数据的方法

RMAN无法直接找回被delete的行,只能通过不完全恢复将整个数据库回退到指定时间点,代价是丢失之后所有变更。优先使用闪回查询或回收站。若必须用RMAN,需有完整备份和归档日志,恢复后需打开resetlogs并导出数据,操作复杂且风险高。

时间:2026-07-16 17:54
Oracle 11g中监控RMAN备份任务实时剩余时间的完整方法

Oracle 11g中监控RMAN备份任务实时剩余时间的完整方法

在Oracle11g中监控RMAN备份剩余时间,不应仅依赖v$session_longops的time_remaining字段,因其存在子任务重置、版本缺陷等不准确性。需结合sofar totalwork计算的百分比进行交叉验证,并添加OPNAMELIKE RMAN% 等过滤条件。RAC环境须使用GV$视图并指定INST_ID,以确保准确性,避免错误判断。

时间:2026-07-16 17:54
热门专题
更多
刀塔传奇破解版无限钻石下载大全 刀塔传奇破解版无限钻石下载大全
洛克王国正式正版手游下载安装大全 洛克王国正式正版手游下载安装大全
思美人手游下载专区 思美人手游下载专区
好玩的阿拉德之怒游戏下载合集 好玩的阿拉德之怒游戏下载合集
不思议迷宫手游下载合集 不思议迷宫手游下载合集
百宝袋汉化组游戏最新合集 百宝袋汉化组游戏最新合集
jsk游戏合集30款游戏大全 jsk游戏合集30款游戏大全
宾果消消消原版下载大全 宾果消消消原版下载大全
  • 热门数据榜