goal
draw first place to fifth place tickets. a user can’t win multiple places. If a user hasn’t placed, then all of their tickets must be considered in the draw.
progress
I can draw one winner, but not all five.
idea
I could repeat the query 4 more times and eliminate the previous user_ids each time. But there’s got to be a better way.
question
how do I draw all 5 place tickets?
tickets table
- id
- user_id
- amount
- created_at
this is my query
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;
2
Answers
You can use
generate_series
to create one roll of the dice per ticket. Then select the five users with the highest rolls:Example at DB Fiddle
There’s no need to actually spawn the tickets and select from among them. The
amount
already dictates the probability. Demo at db<>fiddle:It’s nice to have a purely arithmetic solution but this will quickly run into a numeric underflow problem when you hit high enough
amount
(like 56).