CREATE DEFINER=`root`@`%` PROCEDURE `random_students`()
BEGIN
DECLARE done INT DEFAULT 0;
DECLARE var_come_from VARCHAR(255);
DECLARE come_from_cursor CURSOR FOR SELECT come_from FROM eva_development.students GROUP BY come_from;
DECLARE CONTINUE HANDLER FOR SQLSTATE '02000' SET done = 1;
OPEN come_from_cursor;
REPEAT
FETCH come_from_cursor INTO var_come_from;
SELECT * FROM eva_development.students where come_from = var_come_from order by rand() limit 1;
UNTIL done END REPEAT;
CLOSE come_from_cursor;
END
结果报错说:ActiveRecord::StatementInvalid: Mysql::Error: PROCEDURE vc.testsp can’t return a result set in the given context.
到网上搜了一下,发现rails的wiki里面就有一篇讲怎么使用sp的,于是就按部就班的做了,不过网上的教程有点儿过时了,这里稍微做一个介绍:
先保证自己装的是MySql 5.0+版本。
安装native MySql Connector:gem install mysql。
修改rails中的mysql_adapter.rb,文件在$RUBY_ROOT/lib/ruby/gems/1.8/gems/activerecord-$VERSION/lib/active_record/connection_adapters中,具体修改如下:
def self.random_select(student_number)
students = connection.select_sp('call random_students')
students << find_by_sql(['select * from students order by rand() limit ?', student_number - students.length]) unless students.length >= student_number
students.flatten[0, student_number]
end
写了这么多,以为可以万事大吉了,谁知道调用下来,却报了下面这个错误:Commands out of sync; you can't run this command now.这下可不知道怎么办了,搜了一阵子也没有答案。我猜想可能与多结果集有关,于是写了一个单结果集的sp来调用,果然就没有问题。看来我的这个功能还真不能在sql里面做咧,于是只好全部转到ruby里面,不过还好有MySql的RAND()函数,性能不是太差,而且我数据库里面大概就2w数据,不多。
def self.random_select(number = 50)
result = []
students = Student.find_by_sql('select come_from from students group by come_from')
students.each do |student|
result << Student.find_by_sql(['select * from students where come_from = ? order by rand() limit 1', student.come_from])
end
result << Student.find_by_sql(['select * from students order by rand() limit ?', number - students.length]) unless students.length >= number
result.flatten[0, number]
end