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

Ordering by different column depending on value of another column

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

all the passage questions are coming last

我有 40 个测试问题的限制,在 table 我有 50 个段落问题和 70 个普通问题。

How can i write a query to call passage questions in between normal questions.

示例

1.who是美国总统。?(type_id=0)

2.A,B,C 是 3 个学生 Aname 是 "Arun" B name 是 "Mike" C name 是 "Jhon"(type_id=1) 上面的C是谁

3.A,B,C 是 3 个学生 Aname 是 "Arun" B name 是 "Mike" C name 是 "Jhon"(type_id=1) 上面的A是谁

4.Who 是 Facebook 的首席执行官。?(type_id=0)

形成上面的4问题我们会随机选择如果问题1出现rand()没问题当问题2出现在rand()下一道题应该是有顺序的。这意味着下一个问题应该是 3 在该段落问题完成后它应该切换回 rand() 功能

使用下面的,我没有测试过,如果有错误请反馈,我会更正。 $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添加到table,否则这个问题会很慢。

编辑: 修正了顺序(我希望),忘记了 MYSQL 生成 0 到 1 之间的随机数。

这是 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

就这些了

我认为你的数据库设计应该改进,但我将按原样回答你的问题。

我想我有一个相当简单的解决方案,我可以在没有 CTE 的情况下用 portable SQL 表达。

它是这样工作的:让我们为每一行分配两个数字,称它们为 major(一个整数,为了安全起见,我们将其设为十的倍数)和 minor(一个浮点数介于 0 和 1 之间)。对于类型 0 的问题,minor 始终为 0。与同一段落相关的每个类型 1 的问题都得到相同的 major(我们使用带有分组子选择的联接来执行此操作)。然后,我们按两个值的总和对 table 进行排序。

它会很慢,因为它使用文本字段加入。如果每个不同的 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 问题,你可以取消注释 UNION 第一部分的 LIMIT 39。如果您想要至少两个,则说 LIMIT 38,依此类推。与同一篇文章相关的所有类型 1 问题将在一次测试中组合在一起;不能保证数据库中与该段落相关的所有问题都会出现在测试中,但在上面的评论中你提到这可能会被“破坏”。

已编辑:

我在 minor 中添加了少量,只是为了绕过 RAND() returns 恰好为零的罕见但可能的情况。由于 major 以十为单位,因此 minor 现在可能大于一这一事实并不重要。