You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

SQL Server中为每个客户随机选取10%行(向上取整)的方法

问题描述

现有一张商品销售表products_sold,表结构及示例数据如下:

row_idcustomerproductdate_sold
1customer_1thingamajig01.01.2023
2customer_12whosi-whatsi03.01.2023
3customer_1watchamacallit04.01.2023
4customer_4whosi-whatsi06.01.2023
............

表中每一行对应一件商品,需求如下:

  • 在SQL Server中为每个客户随机选取10%的行,选取行数需向上取整(例如客户有12行数据时,需选取2行)
  • 每个至少购买一件商品的客户都要出现在结果表中

举例:customer_1共订购100件商品,customer_2订购50件,customer_3订购17件,结果表应有10+5+2=17行。

初始思路是创建临时表计算每个客户所需行数,再通过游标循环选取随机行插入最终表,代码如下:

drop table if exists #row_counts

select
    customer,
    ceiling(convert(decimal(10, 2), count(product)) / 10) as row_count
into #row_counts
from products_sold
group by customer

-- 后续通过游标循环#row_counts,将随机行插入最终表
-- 用order by newid()实现随机排序

但该方案效率较低,寻求更优实现方式。

更优实现方案

可以利用ROW_NUMBER()窗口函数结合随机排序,再关联每个客户的应选行数,一次性完成筛选,避免游标循环的性能问题:

WITH customer_row_counts AS (
    -- 计算每个客户需要选取的行数(向上取整10%)
    SELECT 
        customer,
        CEILING(COUNT(*) / 10.0) AS required_rows
    FROM products_sold
    GROUP BY customer
),
ranked_products AS (
    -- 对每个客户的商品行随机排序并编号
    SELECT 
        ps.*,
        ROW_NUMBER() OVER (PARTITION BY ps.customer ORDER BY NEWID()) AS row_num
    FROM products_sold ps
)
-- 筛选出每个客户前required_rows行的数据
SELECT rp.*
FROM ranked_products rp
JOIN customer_row_counts crc 
    ON rp.customer = crc.customer
WHERE rp.row_num <= crc.required_rows;

方案说明

  1. customer_row_counts CTE:先统计每个客户的总商品数,用COUNT(*) / 10.0确保浮点运算精度,再通过CEILING函数完成向上取整,得到每个客户的应选行数
  2. ranked_products CTE:对每个客户的所有商品行,用NEWID()生成随机值实现无序排序,再用ROW_NUMBER()为每行分配唯一序号
  3. 最终通过关联两个CTE,筛选出每个客户序号小于等于应选行数的记录,直接得到符合要求的结果集

这个方案全程基于集合运算,相比游标循环效率提升明显,尤其在数据量较大时优势突出,同时能保证所有有购买记录的客户都出现在结果中(哪怕只有1件商品也会被选中)。

内容的提问来源于stack exchange,提问作者user15634990

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.04 01:00:53