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

如何用PostgreSQL抽取5名不重复的抽奖获奖者?

解决方案

要实现一次查询抽取5个不重复的获奖用户,同时保证每个用户的所有ticket都参与抽奖、中奖概率与ticket数量成正比,可以使用以下优化后的SQL:

WITH gen_tickets AS (
    -- 将每个用户的ticket展开为单独行,确保每个ticket都有平等参与机会
    SELECT user_id, amount, created_at
    FROM tickets
    CROSS JOIN LATERAL generate_series(1, CAST(amount AS INTEGER))
),
shuffled_tickets AS (
    -- 对所有展开后的ticket进行随机排序
    SELECT user_id, amount, created_at,
           ROW_NUMBER() OVER (ORDER BY random()) AS global_rn
    FROM gen_tickets
),
user_first_entry AS (
    -- 标记每个用户在随机序列中的第一次出现记录
    SELECT *,
           ROW_NUMBER() OVER (PARTITION BY user_id ORDER BY global_rn) AS user_entry_rn
    FROM shuffled_tickets
)
-- 筛选出每个用户的首次出现记录,取前5个即为5名获奖者
SELECT user_id, amount, created_at
FROM user_first_entry
WHERE user_entry_rn = 1
ORDER BY global_rn
LIMIT 5;

方案说明

  1. 展开ticket:通过generate_series将每个用户的amount(ticket数量)拆分为单独行,确保每一张ticket都有平等的随机选中机会,符合“未获奖用户所有ticket全部参与抽奖”的要求。
  2. 全局随机排序:对所有展开后的ticket按随机顺序排序,保证抽奖的公平性。
  3. 去重用户:通过PARTITION BY user_id给每个用户的记录标记序号,只保留每个用户在随机序列中的第一条记录,确保同一用户不会重复获奖。
  4. 抽取5个名额:取前5条符合条件的记录,即为最终的5名获奖者。

对比原有方案的优势

  • 无需重复执行查询并手动排除已中奖用户,一次查询即可完成,效率更高且避免了并发场景下的重复中奖风险。
  • 严格保证每个ticket的权重,用户中奖概率与持有的ticket数量完全成正比,符合抽奖逻辑的公平性。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.02 21:16:17