Как случайным образом выбрать ряд на основе количества билетов, которые у вас есть - PullRequest
0 голосов
/ 27 мая 2020

У меня есть таблица под названием my_users

my_id | name | raffle_tickets
1     | Bob  | 3
2     | Sam  | 59
3     | Bill | 0
4     | Jane | 10
5     | Mike | 12

Как видите, Sam имеет 59 билетов, поэтому у него самые высокие шансы на выигрыш. Шанс на выигрыш:

  • Sam = 59/74
  • Bob = 3/74
  • Jane = 10/74
  • Bill = 0/74
  • Mike = 12/74

PS: 74 - это общее количество билетов в таблице (чтобы вы знали Я не случайно выбрал 74)

Исходя из этого, как я могу случайным образом выбрать победителя, но гарантировать, что у тех, у кого больше лотерейных билетов, больше шансов быть выбранным случайным образом? Затем у победителя, которого выбрали, вычитается 1 билет из его общего количества билетов

UPDATE my_users
SET raffle_tickets = raffle_tickets - 1
WHERE my_id = --- Then I get stuck here...

Версия сервера: 5.7.30

Ответы [ 2 ]

1 голос
/ 27 мая 2020

Для MySQL 8 +

WITH 
cte1 AS ( SELECT name, SUM(raffle_tickets) OVER (ORDER BY my_id) cum_sum
          FROM my_users ),
cte2 AS ( SELECT SUM(raffle_tickets) * RAND() random_sum  
          FROM my_users )  
SELECT name
FROM cte1
CROSS JOIN cte2
WHERE cum_sum >= random_sum
ORDER BY cum_sum LIMIT 1;

Для 5 +

SELECT cte1.name
FROM ( SELECT t2.my_id id, t2.name, SUM(t1.raffle_tickets) cum_sum
       FROM my_users t1
       JOIN my_users t2 ON t1.my_id <= t2.my_id
       WHERE t1.raffle_tickets > 0
       GROUP BY t2.my_id, t2.name ) cte1
CROSS JOIN ( SELECT RAND() * SUM(raffle_tickets) random_sum
             FROM my_users ) cte2
WHERE cte1.cum_sum >= cte2.random_sum
ORDER BY cte1.cum_sum LIMIT 1;

fiddle

0 голосов
/ 27 мая 2020

Вы хотите получить взвешенную выборку из случайной выборки. Для этой цели, вероятно, наиболее эффективным решением являются переменные:

select u.*
from (select u.*, (@t := @t + raffle_tickets) as running_tickets
      from my_users u cross join
           (select @t := 0, @r := rand()) params
      where raffle_tickets > 0
     ) u 
where @r >= (running_tickets - raffle_tickets) / @t and
      @r < (running_tickets / @t);

Это вычисляет текущую сумму билетов, а затем делит ее на количество билетов, чтобы получить число от 0 до 1. Например, это может привести к:

my_id   name    raffle_tickets  running_tickets       running_tickets / @t
1       Bob          3                3               0.03571428571428571
2       Sam         59               62               0.7380952380952381
4       Jane        10               72               0.8571428571428571
5       Mike        12               84               1

Порядок исходных строк не имеет значения - вот почему в подзапросе нет упорядочения.

Затем соотношение используется с rand() для выбора конкретной строки.

Обратите внимание, что во внешнем запросе @t - это общее количество билетов.

Здесь - скрипт db <>.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...