在业务数据处理中,分组内数据抽样是常见需求,比如按商品类目分组抽取每个类目的热销商品样本,或者按部门分组抽取每个部门的员工绩效样本。借助SQL的RAND函数和ROW_NUMBER函数,可以高效实现这个需求。
核心函数说明
实现分组内抽样需要用到两个关键函数,先了解它们的作用:
- RAND函数:用于生成0到1之间的随机浮点数,每次调用结果随机,可作为排序的随机依据。
- ROW_NUMBER函数:窗口函数,用于给每个分组内的行按指定排序规则生成连续的序号,序号从1开始递增。
实现步骤拆解
整体实现逻辑分为三步:
第一步:给每个分组内的数据生成随机排序
使用RAND函数作为ROW_NUMBER的排序依据,让每个分组内的数据随机排列,避免固定顺序导致抽样结果偏差。
第二步:为每个分组内的行生成随机序号
结合PARTITION BY子句按目标分组字段拆分窗口,再用ORDER BY RAND()对每个窗口内的数据随机排序,最后用ROW_NUMBER生成序号。
第三步:按序号筛选样本
根据需要的抽样数量,筛选序号小于等于目标数量的行,即可得到每个分组内的随机样本。
完整代码示例
假设我们有一个用户表user_info,包含user_id(用户ID)、region(所属地区)、register_time(注册时间)字段,现在需要按region分组,每个地区随机抽取2个用户样本,实现SQL如下:
-- 按地区分组,每个地区随机抽取2个用户
WITH temp_table AS (
SELECT
user_id,
region,
register_time,
-- 按地区分组,组内按随机数排序生成序号
ROW_NUMBER() OVER (PARTITION BY region ORDER BY RAND()) AS rn
FROM user_info
)
SELECT
user_id,
region,
register_time
FROM temp_table
WHERE rn <= 2;
如果需要抽取每个分组内30%的数据,可以结合COUNT窗口函数计算每个分组的总数据量,再按序号比例筛选:
-- 按地区分组,每个地区抽取30%的用户样本
WITH temp_table AS (
SELECT
user_id,
region,
register_time,
-- 组内随机序号
ROW_NUMBER() OVER (PARTITION BY region ORDER BY RAND()) AS rn,
-- 每个地区的总用户数
COUNT(user_id) OVER (PARTITION BY region) AS total_cnt
FROM user_info
)
SELECT
user_id,
region,
register_time
FROM temp_table
-- 筛选序号小于等于总数量30%的行
WHERE rn <= CEIL(total_cnt * 0.3);
注意事项
- RAND函数生成的随机数在每次查询时可能不同,如果需要固定抽样结果,可以将RAND的种子固定,比如使用RAND(123),但不同数据库对RAND种子支持有差异,需参考对应数据库文档。
- 如果分组内数据量小于抽样数量,会返回该分组内的所有数据,不会报错。
- 该方法适用于大部分支持窗口函数的关系型数据库,比如MySQL 8.0+、PostgreSQL、SQL Server、Oracle等。
分组内抽样的核心是先通过随机排序打乱组内数据顺序,再通过序号筛选,RAND和ROW_NUMBER的组合可以灵活适配不同的抽样比例和抽样数量需求。
SQL分组抽样RAND函数ROW_NUMBER函数数据抽样修改时间:2026-07-01 07:48:22