2017-01-28 11 views
1

Я имею эту таблицу структуру:Mysql RAND() на основе некоторых других значений

id | product | value 
-----+---------+-------- 
    1 | test1 | 10 
-----+---------+-------- 
    2 | test2 | 30 
-----+---------+-------- 
    3 | test3 | 25 
-----+---------+-------- 
    4 | test4 | 20 
-----+---------+-------- 
    5 | test5 | 15 
-----+---------+-------- 
    6 | test6 | 35 
-----+---------+-------- 

Это некоторые продукты, которые я хочу, чтобы рекомендовать своим пользователям, и я заинтересуют, чтобы показать 4 продукта на моей домашней странице (не все из них), самые ценные продукты с исключение.

Поэтому обычно я хочу показать все время на этом продукте: test6, test2, test3, test4. Единственная проблема заключается в том, что я хочу время от времени отображать некоторые другие продукты, но с более низкой скоростью. Так что, если бы я этого не хотел, я бы, вероятно, order by value desc. Но дело в том, что я не хочу, чтобы мои пользователи скучали, чтобы постоянно видеть одни и те же продукты, я хочу время от времени вставлять один или два других продукта в свой список.

Теперь я знаю, что mysql имеет функцию RAND(), но я не знаю, как я мог бы использовать это, чтобы сделать запрос, чтобы сделать именно то, что я хочу.

Matematically он должен работать так:

Мы добавляем все значения 10+30+25+20+15+35 = 135 совмещены, мы применим правило третей, чтобы увидеть случайную скорость для каждого продукта.

135 = 100% 
------------ 
10 = 7.4% 
30 = 22.2% 
25 = 18.5% 
20 = 14.8% 
15 = 11.1% 
35 = 25.9% 

Так считая это проценты, я хочу, чтобы сделать запрос, который будет возвращать список из 4 продуктов с использованием случайным, но и с учетом, какой продукт имеет больше шансов появляться на основе этих процентов.

Не спрашивайте меня, что я пробовал, потому что я не эксперт mysql, я знаю, как это сделать на PHP, но я хочу знать, возможно ли это, используя только mysql и как я могу это сделать.

ответ

1

Вы можете сделать это с помощью переменных. Возьмите накопленную сумму, нормализовать ее, а затем использовать rand():

select t.* 
from (select t.*, (@v := @v + value) as running_value 
     from t cross join 
      (select @v := 0) params 
    ) t cross join 
    (select sum(value) as sum_value 
     from t 
    ) total 
order by (rand() between (t.running_value - t.value)/total.sum_value and t.running_value/total.sum_value) desc, 
     rand(); 

выше может быть упрощена. Кроме того, rand() в order by может быть повторно рассчитан много раз. Я думаю, что это лучше:

select t.* 
from (select t.*, (@v := @v + value) as running_value, rand() as rnd 
     from t cross join 
      (select @v := 0) params 
    ) t 
order by (rnd between (t.running_value - t.value)/@v and t.running_value/@v) desc; 

EDIT:

Теперь, когда я думаю об этом, бинарный результат в order by вполне правильно заказать по. Это подходит для , выбрав одну строку, но не обязательно для заказа.

Я думаю, что это лучший подход:

select t.* 
from (select t.*, rand() as rnd 
     from t 
    ) t 
order by rnd * t.value desc; 
+0

Спасибо за быстрый ответ. Я попробую это. Один маленький вопрос. Рекомендуется ли это, или быстрее, используя php? Я имею в виду, вы призываете меня использовать этот запрос? – paulalexandru

+0

Второй запрос должен быть таким же хорошим или лучше, чем делать это в php. –

+0

# 1064 - У вас есть ошибка в синтаксисе SQL; проверьте руководство, соответствующее версии сервера MariaDB, для правильного синтаксиса для использования рядом с «desc» в строке 6 – paulalexandru