根据另一列的值按不同列排序

时间:2016-12-15 06:23:36

标签: php mysql sql random sequence

TABLE CONSIST PASSAGE AND NORMAL QUESTIONS

有两种类型的问题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()功能

3 个答案:

答案 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

这就是全部