2010-03-30 2 views
3

У меня есть таблица, которая описывает множество объектов в моей системе (т. Е. Зонтик, сапоги, сумка, что угодно). Каждый из этих объектов должен иметь четкую распространенность или заболеваемость. Например, зонтик реже, чем сапоги. Исходя из этих факторов, мне нужно случайным образом выбрать один объект (включая пустой или «не найденный объект») на основе этого значения заболеваемости.Выберите случайную строку из таблицы, но с коэффициентом?

Yikes. Имеют смысл?

+0

Какова должна быть вероятность выбора объекта? Это хранится в базе данных или является жестко запрограммированной константой? –

+0

Вероятно, как постоянный знак. – Don

ответ

0

Я собираюсь изменить ответ symcbean для этого, +1 для symcbean.

SELECT * FROM some_table 
WHERE (100*RAND()) < some_table.percent_probability

Это вернет ВСЕ результаты, которые соответствуют вероятности, которую вы интуитивно хотите назначить им. Например, 5 объектов с вероятностью 20 будут возвращены в 20% случаев. Объекты со значением 90 будут возвращены в 90% случаев.

Таким образом, ваш результат будет более чем одним объектом, но вы сохранили редкие из них так часто. Так что теперь просто возьмите один из ваших результатов наугад. Самый простой способ будет придерживаться их в массиве и:

$items = array(); // assuming you've already filled $items with your 
        // query results, one item for each array key 

$count = count($items); 

$chosen_key = rand(1,$count)-1; 

$chosen_item = $items[$chosen_key];
+0

Большое спасибо: я пробую это быстро, и это выглядит хорошо, но я получаю ошибку смещения, когда возвращается только один результат? "Сообщение: Неопределенное смещение: 1" – Don

+0

Me = dumb. Понял. Функция rand() начиналась с 1 и не пропускала первый ключ в [0]. – Don

+0

Отредактировано для исправления ошибки Undefined offset. Спасибо что подметил это. –

1
SELECT * FROM some_table 
WHERE (100*RAND()) > some_table.percent_probability 
LIMIT 1 

.... и вероятность выбора сохраняется в поле процента_проблемы.

C.

+0

Это звучит работоспособно, но вводит в заблуждение. Например, если у вас есть 5 объектов, каждый из которых имеет значение 20 в процентах (считая, что каждый из них должен появиться в 20% случаев), то один элемент будет возвращен в 80% случаев, ничего не будет возвращено в 20% случаев и остальные 4 элемента никогда не будут возвращены. Вы должны были бы дать предметам вероятность 0, 20, 40, 60 и 80 для каждого иметь равные шансы. –

+0

@Syntax Ошибка: да, вы частично правы - на размышлениях математика немного сложнее, чем вы предполагаете, но легко фиксируется путем случайного упорядочения и перемещения фильтра от того, где (до сортировки), к предложению (т.е. после). – symcbean

1

Если у вас есть записи-редко для чтения многих сценария (то есть изменить объекты и вероятность редко) вы можете предварительно вычислите значения вероятности так, чтобы, если у вас есть одно случайное значение, вы можете однозначно решить, какой объект выбрать (с одним выбором, без сортировки, без сравнения всех необходимых записей).

E.g. (Вероятности в за мельницу)
зонтичных: 500 ‰ шанса
сапог: 250 ‰ случайностей
ранец: 100 ‰ шанса
независимо: 100 ‰ шанса
"ничего": 50 ‰ шанса

Случайных число от 0 до 499 означает «зонтик», выбрано 500-749 «сапог» и так далее.

INSERT INTO foo (name, randmin, randmax) VALUES 
    ('umbrella', 0, 499), 
    ('boots', 500, 749), 
    ('satchel', 750, 849), 
    ('whatever', 850, 949) 

Каждый раз, когда вы добавляете объект или изменяете вероятности, пересоздайте эту таблицу.

Тогда все, что вам нужно, это запрос как

SELECT 
    f.name 
FROM 
    ( 
    SELECT Round(Rand()*1000) as r  
) as tmp 
JOIN 
    foo as f 
ON 
    r BETWEEN f.randmin and f.randmax 
LIMIT 
    1 

Только одна случайная величина должна быть сгенерирован и MySQL может использовать индекс (randmin, RANDMAX), чтобы найти запись быстро.

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