postgresql抽奖查询

wxclj1h5  于 2024-01-07  发布在  PostgreSQL
关注(0)|答案(3)|浏览(117)

goal抽取第一名到第五名的门票。一个用户不能赢得多个名额。如果一个用户没有下注,那么他们所有的门票都必须在抽奖中考虑。

idea我可以再重复查询4次,每次都删除前面的user_id。但一定有更好的方法。
问题我如何抽取所有5个位置的门票?
门票表

  • ID
  • 用户标识
  • 创建于
    这是我的问题
WITH gen_tickets AS (
    -- Use `generate_series()` to create a row for each ticket
    SELECT user_id, amount, created_at
    FROM tickets
    CROSS JOIN LATERAL generate_series(1, CAST(amount AS INTEGER))
),
shuffle AS (
    SELECT user_id, amount, row_number() OVER (ORDER BY random()) AS rn
    FROM gen_tickets
)
SELECT * FROM shuffle
ORDER BY RANDOM()
LIMIT 1;

字符串

v2g6jxz6

v2g6jxz61#

您可以使用generate_series为每张票创建一次掷骰。然后选择掷骰数最高的五个用户:

SELECT  *
FROM    (
        SELECT  user_id
        ,       max(random()) as roll
        FROM    tickets
        CROSS JOIN
                generate_series(1, amount) gs(num)
        GROUP BY
                user_id
        ) s
ORDER BY
        roll DESC
LIMIT   5

字符串
Example at DB Fiddle

snz8szmq

snz8szmq2#

不需要实际生成票据并从中进行选择。amount已经决定了概率:demo at db<>fiddle:

select row_number()over(order by random()::numeric^amount::numeric),
       user_id 
from tickets 
limit 5;

字符串
解决@Andomar关于initial version的评论,显示当前版本的here's an additional set of tests提供了足够的概率。

gmxoilav

gmxoilav3#

最后我尝试了TSCAmerica.com的建议。但不幸的是,它产生了重复。

WITH gen_tickets AS (
    -- Use `generate_series()` to create a row for each ticket
    SELECT user_id, amount, created_at, 
    DENSE_RANK() OVER (
        ORDER BY user_id
    ) dense_rank_number
    FROM tickets
    CROSS JOIN LATERAL generate_series(1, CAST(amount AS INTEGER))
),
shuffle AS (
    SELECT user_id, amount, dense_rank_number, row_number() OVER (ORDER BY random()) AS rn
    FROM gen_tickets
)
SELECT dense_rank_number, user_id, amount
FROM shuffle
GROUP BY dense_rank_number, user_id, amount
LIMIT 5;

字符串

相关问题