根据另一列的值按不同列排序
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
现在可能大于一这一事实并不重要。
有两种类型的问题 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
现在可能大于一这一事实并不重要。