有两种类型的问题1.Passage和2.Normal问题。
通常在测试中,我想选择包含type_id=0
的随机问题,如果type=1
问题出现,那么下一段应该与该问题相关(理解问题应该按顺序进行)。通过使用以下查询,我可以得到问题
SELECT *
FROM tbl_testquestion
ORDER BY
CASE
WHEN type_id=0 THEN RAND()
WHEN type_id=1 THEN qu_id
END ASC
所有段落问题都将持续到最后
我有40个测试问题的限制,在表格中我有50个问题和70个普通问题。
如何在正常情况下编写查询来调用通过问题 的问题。
示例
1.谁是美国总统。?(type_id = 0)
2.A,B,C是3名学生Aname是“Arun”B名称是“Mike”C名称是“Jhon”(type_id = 1) 谁是上述文章中的C
3.A,B,C是3名学生Aname是“Arun”B名称是“Mike”C名称是“Jhon”(type_id = 1) 谁是上述段落中的A
4.谁是Facebook的CEO。?(type_id = 0)
形成上面的 4 问题,如果问题 1 ,rand()
问题 2 ,我们会随机选择进入rand()
下一个问题应该是顺序的。这意味着下一个问题应该是 3 在完成通过问题之后它应该切换回rand()
功能
答案 0 :(得分:4)
我认为应该改进数据库的设计,但我会回答你的问题。
我认为我有一个相当简单的解决方案,我可以在没有CTE的便携式SQL中表达。
它以这种方式工作:让我们为每一行分配两个数字,称之为major
(一个整数,只是为了安全,让它成为十的倍数)和minor
(一个介于0之间的浮点数) 1)。对于0型问题,minor
始终为0.与同一段落相关的每个类型1问题都会得到相同的major
(我们使用分组子选择的连接执行此操作)。然后,我们按两个值的总和对表格进行排序。
它会很慢,因为它使用文本字段连接。如果每个不同的passage_description
都有一个整数id用于连接,那就更好了。
我假设所有类型0问题都为空或passage_description
,而类型1问题则为非空(否则没有意义。)
我假设您有一个RAND()
函数,它产生的浮点值介于0和1之间。
我们走了:
SELECT u.qu_id, u.type_id,
u.passage_description, u.passage_image,
u.cat_id, u.subcat_id,
u.question, u.q_instruction, u.qu_status
FROM (
SELECT grouped.major, RAND()+0.001 AS minor, t1.*
FROM tbl_testquestion t1
JOIN (SELECT 10*FLOOR(1000*RAND()) major, passage_description
FROM tbl_testquestion WHERE type_id = 1
GROUP BY passage_description) grouped
USING (passage_description)
-- LIMIT 39
UNION
SELECT 10*FLOOR(1000*RAND()) major, 0 minor, t0.*
FROM tbl_testquestion t0 WHERE type_id = 0
) u ORDER BY u.major+u.minor ASC LIMIT 40;
上述查询未经修改,您只能获得一种类型的问题的可能性很小。如果您想确定至少有一个0型问题,可以取消注释LIMIT 39
第一部分的UNION
。如果你想要至少两个,那么说LIMIT 38
,依此类推。与同一段落相关的所有类型1问题将在一个测试中组合在一起;不保证数据库中与该段落有关的所有问题都将在测试中,但在上面的评论中,你提到这可能是“破产”。
<强>编辑:强>
我向minor
添加了少量资金,只是为了绕过罕见但可能的情况,其中RAND()返回正好为零。由于major
增加了几十,minor
现在可能大于一的事实并不重要。
答案 1 :(得分:0)
使用以下内容,我还没有对此进行测试,如果有任何错误请报告,我会更正。 $ r是PHP为此查询生成的随机值。你可以做$ r = rand();在调用查询之前
SELECT * FROM (
UNION((
SELECT *, RAND()*(SELECT COUNT(*) FROM tbl_testquestions) as orderid
FROM tbl_testquestion
WHERE type_id=0
ORDER BY orderid
LIMIT 20
),(
SELECT *, MD5(CONCAT('$r', passage_description)) as orderid
FROM tbl_testquestion
WHERE type_id=1
ORDER BY orderid
LIMIT 20
))
) AS t1
ORDER BY orderid
解释:orderid会将type_id = 1个条目放在一起,因为它会为相同的段落问题生成相同的随机序列。
警告:除非您在表格中添加passage_id,否则此问题的效果会非常缓慢。
编辑:修正了排序(我希望),忘了MYSQL生成0到1之间的随机数。
答案 2 :(得分:0)
这是mysql的解决方案,
抱歉,它不是那么可读,因为mysql不支持像sql-server这样的CTE。
也许你可以将sql-server CTE语法与底层进行比较,以便更好地理解它是如何工作的。
select
d.*
, o.q_ix, rnd_ord -- this is only for your reference
from (
select *, floor(rand()*1000) as rnd_ord -- this is main order for questions and groups
from (
select * from (
select
(@r1 := @r1 - 1) as q_ix, -- this is row_number() (negative so we can keep group separated)
passage_description, 0 qu_id, type_id
from (
select distinct passage_description, type_id
from tbl_testquestion,
(SELECT @r1 := 0) v, -- this is the trick for row_number()
(SELECT @rnd_limit := -floor(rand()*3)) r -- this is the trick for dynamic random limit
where type_id=1
) p
order by passage_description -- order by for row_number()
) op
where q_ix < @rnd_limit
union all
select * from (
select
(@r2 := @r2 + 1) as q_ix, -- again row_number()
'' as passage_description, qu_id, type_id
from tbl_testquestion,
(SELECT @r2 := 0) v -- var for row_number
where type_id=0
order by qu_id -- order by for row_number()
) oq
) q
) o
-- look at double join for questions and groups
join tbl_testquestion d on
((d.passage_description = o.passage_description) and (d.type_id=1))
or
((d.qu_id=o.qu_id) and (d.type_id=0))
order by rnd_ord
limit 40
这是更易读的sql-server语法:
;with
p as (
-- select a random number of groups (0-2) and label groups (-1,-2)
select top (abs(checksum(NEWID())) % 3) -ROW_NUMBER() over (order by passage_description) p_id, passage_description
from (
select distinct passage_description
from d
where type_id=1
) x
),
q as (
-- label questions (1..n)
select ROW_NUMBER() over (order by qu_id) q_ix, qu_id
from d
where type_id=0
),
o as (
-- calculate final order
select *, ROW_NUMBER() over (order by newid()) rnd_ord
from (
select p.q_ix, passage_description, 0 qu_id from p
union all
select q.q_ix, '', qu_id from q
) x
)
select top 40
d.*
, o.rnd_ord, o.q_ix
from o
join d on
((d.passage_description = o.passage_description) and (d.type_id=1))
or
((d.qu_id = o.qu_id) and (d.type_id=0))
order by
rnd_ord
这就是全部