这是题目的实体类
private Integer id; private Integer type;//题型 单选,多选 private String category;//类型 数据字典配置 private String problem;//问题 private String choose1;//选择1 private String choose2; private String choose3; private String choose4; private String choose5; private String choose6; private String choose7; private String choose8; private String answer;//答案
卷子的实体类
private Integer id; private String title; private String problemNo;//题目,逗号分割 private Integer extract;//抽题个数
需求:已经录入若干提,其中每题的类型不完全相同,例如有的题目是语文,有的是数学之类的。
抽取其中若干题,必然是小于录入题的,必须保证每种类型的题都被抽取到,且希望能根据不同类型的题目均匀抽取;
例如录入40题,抽取10题。
假如语文,数学,物理,化学各是16,12,8,4。那么抽取语文,数学,物理,化学应当各是4,3,2,1道题。
假如语文,数学,物理,化学各是19,19,1,1。那么抽取语文,数学,物理,化学应当各是4,4,1,1道题。
作出最优解。
解决方案,因为涉及到类型,且类型未均匀分布。避免多次访问数据库,使用存储过程;
CREATE DEFINER=`root`@`%` PROCEDURE `rand_question`(in pid int, out idstr VARCHAR(128)) begin #declare pno VARCHAR(32); declare qp VARCHAR(32); DECLARE ques_ext int DEFAULT 1; DECLARE ques_sum int DEFAULT 0; DECLARE qpid VARCHAR(32); DECLARE qpCategory VARCHAR(32); DECLARE qpSum INT(10); DECLARE q_sum INT(10) DEFAULT 0; DECLARE rem INT(10) DEFAULT 0; declare done int default -1; -- 用于控制循环是否结束 #SELECT q.problem_no INTO pno FROM tb_multi_questionnaire q WHERE del_flag = ‘0‘ and q.id = pid; # 声明游标 DECLARE qp_cursor CURSOR FOR SELECT qp.category,COUNT(1) FROM tb_multi_question_problem qp WHERE del_flag = ‘0‘ and FIND_IN_SET(qp.id,(SELECT q.problem_no FROM tb_multi_questionnaire q WHERE del_flag = ‘0‘ and q.id = pid)) GROUP BY qp.category; # 当游标到达尾部时,mysql自动设置done=1 DECLARE CONTINUE HANDLER FOR NOT found SET done = 1; SELECT q.extract into ques_ext FROM tb_multi_questionnaire q WHERE del_flag = ‘0‘ and q.id = pid; SELECT COUNT(1) into ques_sum FROM tb_multi_question_problem qp WHERE del_flag = ‘0‘ and FIND_IN_SET(qp.id,(SELECT q.problem_no FROM tb_multi_questionnaire q WHERE del_flag = ‘0‘ and q.id = pid)); SET q_sum = ques_ext; set idstr = ‘‘; # 打开游标 OPEN qp_cursor; # 开始循环 qpLoop : LOOP # 移动游标并赋值 FETCH qp_cursor INTO qpCategory,qpSum; IF done = 1 THEN LEAVE qpLoop; END IF; -- 计算判定 set rem = floor(qpSum*ques_ext/ques_sum); IF rem < 1 THEN SET rem = 1; END IF; SELECT group_concat(id) INTO qpid FROM (SELECT id FROM tb_multi_question_problem WHERE del_flag = ‘0‘ and category = qpCategory and id >= (SELECT FLOOR(RAND()*(SELECT MAX(id) FROM tb_multi_question_problem WHERE del_flag = ‘0‘ and category = qpCategory))) ORDER BY id LIMIT 1,rem) as a; set idstr = CONCAT(idstr,qpid,‘,‘); set q_sum = q_sum-rem; -- 计算判定结束 # 循环结束 END LOOP qpLoop; # 关闭游标 CLOSE qp_cursor; IF q_sum > 0 THEN SELECT group_concat(id) INTO qpid FROM (SELECT id FROM tb_multi_question_problem WHERE del_flag = ‘0‘ and !FIND_IN_SET(id,idstr) and id >= (SELECT FLOOR(RAND()*(SELECT MAX(id) FROM tb_multi_question_problem WHERE del_flag = ‘0‘ and !FIND_IN_SET(id,idstr)))) ORDER BY id LIMIT 1,q_sum) as a; set idstr = CONCAT(idstr,qpid,‘,‘); END IF; #select q_sum,idstr; #SELECT pno; #set idstr = pno; end
得到所得的值有两种方法,第一种:
使用map传递接受参数
mapper.xml
<resultMap type="java.util.HashMap" id="resultMap"> <result column="id" property="id" javaType="java.lang.Integer" jdbcType="INTEGER"/> <result column="idstr" property="idstr" javaType="java.lang.String" jdbcType="VARCHAR"/> </resultMap> <select id="randomList" statementType="CALLABLE" parameterType="java.util.HashMap" resultMap="resultMap"> { call rand_question( #{id,jdbcType=INTEGER,mode=IN}, #{idstr, jdbcType=VARCHAR,mode=OUT}) } </select>
service
public List<QuestionProblem> randomList(Map<String, Object> param) { questionProblemDao.randomList(param); return questionProblemDao.getListByIds((String)param.get("idstr")); }
如上,通过param传参,也通过param接受参数;
类似于selectkey,我之前写的博客https://www.cnblogs.com/zhengyuanyuan/p/10616616.html
第二种通过javabean,有时间再补充
原文:https://www.cnblogs.com/zhengyuanyuan/p/10731317.html