2016-07-06 3 views
1

Я пытаюсь написать запрос, который будет выбирать количество статей из таблицы случайным образом, но статьи имеют взвешенные шансы на выбор. я придумал решение, но это кажется неуклюжим для меня, и мне было интересно, есть ли у кого-нибудь идеи о том, как сделать это лучше. Мне нужно как минимум 1 статья, но было бы полезно, если бы запрос сразу возвращал несколько.выбор взвешенного случайного распределения из таблицы mysql

вот мой подход:

стол -

mysql> describe randomiser; 
+---------+----------------------+------+-----+---------+----------------+ 
| Field | Type     | Null | Key | Default | Extra   | 
+---------+----------------------+------+-----+---------+----------------+ 
| id  | int(10) unsigned  | NO | PRI | NULL | auto_increment | 
| article | varchar(30)   | YES |  | NULL |    | 
| chance | smallint(5) unsigned | NO | MUL | 1  |    | 
| low  | int(10) unsigned  | NO | MUL | 0  |    | 
| high | int(10) unsigned  | NO |  | 0  |    | 
+---------+----------------------+------+-----+---------+----------------+ 

мое испытание населения -

mysql> select * from randomiser; 
+----+-------------+--------+-----+------+ 
| id | article  | chance | low | high | 
+----+-------------+--------+-----+------+ 
| 1 | common  | 128 | 1 | 128 | 
| 2 | uncommon |  64 | 129 | 192 | 
| 3 | infrequent1 |  32 | 193 | 224 | 
| 4 | infrequent2 |  32 | 225 | 256 | 
| 5 | infrequent3 |  32 | 257 | 288 | 
+----+-------------+--------+-----+------+ 

низкие и высокие значения обновляются при вставке, в любое время кто-то добавляет новая статья к таблице.

мой метод выбора -

SET @t:=(SELECT FLOOR(SUM(chance) * RAND() + 1) FROM randomiser); 
SELECT article FROM randomiser WHERE @t >= low AND @t <= high; 
  1. возможно объединить выбирает в единую, эффективную заявление?
  2. Можно ли написать выбор, который вытащит несколько случайных значений вместо одного?

ПРИМЕЧАНИЕ. - Я совсем не привязан к таблице, как я ее определил; если есть другой вид макета, поэтому он будет более эффективным, я бы хотел знать!

ответ

1

Для одного запроса, вы можете сделать это следующим образом:

SELECT article 
FROM randomiser 
WHERE (SELECT FLOOR(SUM(chance) * RAND() + 1) FROM randomiser) BETWEEN low AND high; 

SQLFiddle Demo

Или использовать INNER JOIN:

SELECT article, `range` 
FROM randomiser 
INNER JOIN (
    SELECT 
     FLOOR(SUM(chance) * RAND() + 1) AS `range` 
    FROM randomiser 
) t 
WHERE `range` >= low AND `range` <= high; 

SQLFiddle Demo

+0

первый, похоже, не работает. он выберет пустой набор, а также два смежных значения. второй, похоже, работает достаточно хорошо. :) Спасибо ! я полагаю, что единственный способ использовать его для получения произвольного количества случайных статей - это вызывать его несколько раз в цикле из управляющей программы, верно? или вы думаете, каким-то образом он может получить несколько случайных значений? –

+0

Я предполагаю, что это может быть сделано с несколькими случайными значениями «диапазона» и присвоением имен другого выхода с использованием 'AS', чтобы отличать их после извлечения, но это также кажется неуклюжим. мне придется подумать об этом еще немного. –

+0

Мне удалось найти решение проблемы, которая возвращает несколько случайных статей, используя вариант второго подхода (используя внутреннее соединение) и 'union'. это, может быть, не самое лучшее, но, похоже, это хорошо. Спасибо за помощь ! –

1

Вы можете использовать приведенный ниже запрос

select t.article from 
(SELECT article, 
case when FLOOR(SUM(chance) * RAND() + 1) between low and high 
     then 1 else 0 end as chance 
FROM randomiser 
group by article) t 
where t.chance = 1 

выше один будет использовать несколько случайных значений

+0

это не похоже на работу. Я получаю следующую ошибку: 'ERROR 1111 (HY000): неверное использование функции группы' –

+0

@ davidfurst я изменил запрос –

+0

@ davidfurst теперь проверяет –

Смежные вопросы