#mysql #cakephp #cakephp-1.3
#mysql #cakephp #cakephp-1.3
Вопрос:
У меня есть таблица профилей, в которой я хотел бы иметь список профилей в случайном порядке, который я выполнил следующим образом:
$this->paginate = array('User' => array('conditions'=>array('User.userstanding_id'=>'1'), 'order' => 'RAND()', 'limit' => '10'));
Единственная функциональность, которой здесь не хватает, заключается в том, что я хотел бы, чтобы профили следовали последовательно, чтобы на следующей странице не было дубликатов, и даже некоторые профили вообще не просматривались, когда вы просматриваете все страницы.
То, что я ищу, — это способ найти случайную отправную точку для запроса, а затем разбить на страницы по порядку, начиная с этой начальной точки. Может быть, за сеанс?
Ответ №1:
RAND()
Функция MySQL может принимать целое число в качестве аргумента для использования в качестве начального числа, всегда выдавая один и тот же результат:
Чтобы продемонстрировать это, вот таблица с 3 строковыми записями в один столбец:
mysql> select * from chartest;
--------
| string |
--------
| AA |
| AB |
| BB |
--------
3 rows in set (0.00 sec)
Если я использую 1 в качестве начального значения для rand()
в моем ORDER BY
, это всегда будет приводить к одному и тому же результату упорядочивания:
mysql> select * from chartest order by rand(1);
--------
| string |
--------
| BB |
| AA |
| AB |
--------
3 rows in set (0.00 sec)
mysql> select * from chartest order by rand(1);
--------
| string |
--------
| BB |
| AA |
| AB |
--------
3 rows in set (0.00 sec)
Если я изменю начальное значение на 2, порядок изменится:
mysql> select * from chartest order by rand(2);
--------
| string |
--------
| AB |
| BB |
| AA |
--------
3 rows in set (0.00 sec)
Выбор исходного кода
Вы могли бы преобразовать идентификатор сеанса пользователя в целое число и передать его в эту функцию, чтобы для этого сеанса результаты всегда были упорядочены одинаковым образом.
Если, например, идентификатор сеанса является хэшем MD5, чтобы избежать необходимости иметь дело с большими (160 битными) целыми числами, которые представляют эти значения, просто удалите символы из строки (используя, например preg_replace ('/[^ds]/', '', $sessionid);
). Затем возьмите первые 5 или около того цифр и преобразуйте их в (int)
для использования в качестве начального значения:
$seed = substr($numeric_id, 0, 5);
Обновить
Чтобы передать параметр в RAND()
функцию при использовании CakePHP, чтобы убедиться, что он обрабатывается как целое число, а не строка, попробуйте использовать следующий синтаксис в вашем $conditions
массиве order
:
'order' => 'RAND(CAST('.$seed.' AS SIGNED))'
Комментарии:
1. cake переводит запрос в этот ПОРЯДОК с помощью
rand(`3`)
и выдает ошибки. Я не добавляю `это автоматически по cake. Я предполагаю, что именно отсюда возникает ошибка… Есть идеи? извините… есть тики вокруг 3…2. Обычно я бы предложил сохранить ваше целое число в соответствующей переменной PHP типа
(int)
и привязать его, а не объединять, но поскольку вы используете cake, попробуйте передать его в соответствии с моим обновлением выше.3. Рад это слышать 🙂 Я не уверен, почему Cake решает исказить ваше
int
вchar
, хотя это не совсем «полезное поведение», не так ли.4. Нет, хех, совсем не полезно… На самом деле мне пришлось добавить пробелы, чтобы обойти это. ‘(‘.$seed.’)’ стал ‘( ‘.$seed.’ )’. Но ваш первоначальный ответ на мой вопрос rand отлично сработал.
Ответ №2:
Я не эксперт в CakePHP, но я полагаю, что если вы вводите функцию RAND на основе сеанса, то функция paginate будет работать со страницы на страницу, используя начальное значение сеанса.
например
назначьте начальное значение при создании сеанса, просто используйте генератор случайных чисел для этого.
$this->paginate = array('User' => array('conditions'=>array('User.userstanding_id'=>'1'), 'order' => 'RAND('.$_SESSION['rndSeed'].')', 'limit' => '10'));