2010-08-10 3 views
1

У меня есть несколько тегов для каждого сообщения. (Очень похоже на SO). Я хочу 20 случайных предметов, не повторяющихся.Rails: получить список случайных элементов из базы данных MySQL

Я знаю, что могу использовать Tags.all.rand (И повторяю 10 раз), однако это не гарантирует уникальность.

И я знаю, что я мог бы использовать SQL-запрос, но так как моя среда разработки использует sqlite как db и MySQL в процессе производства, ORDER by RAND не будет работать для обоих.

Помимо двух разных запросов (Dev & Prod), что еще я могу сделать?

Thanks

ответ

2

Вы можете выбрать случайную выборку из 20 тегов с помощью:

Tag.all.sort_by {rand}[0..19] 

(Благодаря chubas для этого простого решения!)

Недостатком этого является то, что оно будет неэффективным над большим наборы данных. Вы можете улучшить это, выбрав только идентификаторы:

Tag.all(:select => :id).map(&:id).sort_by{rand}[0..19] 
+1

Я всегда использую 'array.sort_by {rand}' для рандомизации массивов. Это лучший способ сделать это (вероятностно?). Мне любопытно – Chubas

+0

Это отличное решение, спасибо. Я отредактировал свой ответ соответственно, спасибо! :) – Olly

2

Почему вы используете две разные базы данных для разработки и производства? Это может привести к дальнейшим проблемам. Возьмем, к примеру, то, что произошло с нами недавно, один из наших разработчиков использовал MySQL и использовал специальный синтаксис LIKE для MySQL, который не работал в нашей производственной базе PostgreSQL.

Мораль истории: Если вы используете что-то другое для разработки, тестирования и/или производства: вы делаете это неправильно.

Следующая: Чтобы получить случайные элементы в MySQL, вы можете: Tag.all(:order => "RAND()", :limit => 10).

+0

Да, я знаю, что это проблема. Я использую SQLite на своем ноутбуке из-за его легкого ресурса. Есть ли запрос или атрибут Rails или функция, которая будет обрабатывать оба? – cbrulak

+0

MySQL должен действительно иметь возможность запускать что угодно. Это не настоящий бог. У меня это на моем нетбуке, и все в порядке. –

2

Ответ Райана делает это, но поставляется с gotcha. Если ваш набор данных очень большой,: order => «RAND()» непрактично (запрос будет выполняться очень медленно). Есть два альтернативных метода: сначала введите все идентификаторы ваших предметов, выберите 20 в случайном порядке, затем выберите эти строки или получите количество элементов в db, выберите один со случайным смещением и повторите (сначала выберите смещения, чтобы не гарантируйте дубликатов).

Подробнее об этом в SQL Antipatterns книга, являясь этой главой в подарок.

BTW: Если вы используете Ruby 1.8+ или Rails 2.3+ (я считаю), существует метод Array#sample, который позволит вам выбирать n элементов rand без повторения, как в вашем первоначальном подходе.

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