从数据集A、B选取无重复ID随机样本的问题排查与解决
问题
我有两个数据集A和B,需求如下:
- 先从A中选取10个ID唯一的随机样本(ID不重复,对应总行数可多于10);
- 再从B中选取10个同样ID唯一的随机样本,且这些ID不能出现在从A选取的样本中。
我执行了以下步骤:
- 从A中获取10个不同ID的样本并取出对应行,存储为A_records:
select * from A t1 inner join (select distinct id from A tablesample(10 rows)) t2 where t1.id = t2.id -- 存储为A_records
- 创建临时视图B_pool,存储B中排除A_records里ID的可用样本池:
create or replace view B_pool as (select distinct id from B where B.Id not in (select distinct ID from A_records)
- 从B_pool中选取样本:
select * from B t1 inner join (select distinct ID from B_pool tablesample(10 rows)) t2 on t1.id = t2.id
按逻辑应该可行,但实际结果里B的样本仍包含A样本中的ID,请问怎么避免这种重复?
解决方案
你的问题根源在于两处逻辑漏洞:
tablesample(10 rows)的抽样缺陷:它是按数据块抽样,无法保证精确抽取10个唯一ID,甚至可能抽到重复ID;若抽样后实际唯一ID数量不足10,后续B的过滤逻辑会直接失效。NOT IN的空值隐患:如果A_records中存在NULL的ID,NOT IN会返回空结果,导致B_pool的过滤完全失效,直接保留B的所有ID。
修正后的执行步骤如下:
步骤1:正确从A抽取10个唯一随机ID并获取对应行
用随机排序+限制数量的方式,精确获取10个唯一ID,避免tablesample的不确定性:
-- 先筛选10个唯一随机ID,再关联获取全量行 WITH A_unique_ids AS ( SELECT DISTINCT id FROM A ORDER BY RANDOM() -- 不同数据库写法有差异,见下方说明 LIMIT 10 ) SELECT A.* INTO A_records FROM A JOIN A_unique_ids ON A.id = A_unique_ids.id;
步骤2:创建正确的B可用样本池
改用NOT EXISTS替代NOT IN,彻底避免空值导致的过滤失效:
CREATE OR REPLACE VIEW B_pool AS SELECT DISTINCT id FROM B WHERE NOT EXISTS ( SELECT 1 FROM A_records WHERE A_records.id = B.id );
步骤3:从B_pool抽取10个唯一随机ID并获取对应行
同样用随机排序+限制数量的方式,确保抽取的ID唯一且不与A重复:
WITH B_selected_ids AS ( SELECT id FROM B_pool ORDER BY RANDOM() -- 对应数据库替换成随机函数 LIMIT 10 ) SELECT B.* FROM B JOIN B_selected_ids ON B.id = B_selected_ids.id;
数据库适配说明
不同数据库的随机排序函数需要替换:
- PostgreSQL:
ORDER BY RANDOM() - MySQL/MariaDB:
ORDER BY RAND() - SQL Server:
ORDER BY NEWID() - Oracle:
ORDER BY DBMS_RANDOM.VALUE()
内容的提问来源于stack exchange,提问作者curiouscoder007
相关产品推荐
相关产品推荐

