考虑这种经典设置:
entry
表:
id(int,PK)
title(varchar 255)
entry_category
表:
entry_id(int)
category_id(int)
category
表:
id(int,PK)
title(varchar 255)
这基本上意味着条目可以在一个或多个类别中(entry_category
表用作MM /连接表)
现在我需要通过RANDOM查询6个唯一的分类以及这些类别中的1个唯一条目!
编辑:澄清:这样做的目的是显示6个随机类别,每个类别有1个随机条目。
正确的结果集如下所示:
category_id entry_id
10 200
20 300
30 400
40 500
50 600
60 700
这是不正确的,因为category_id
列中有重复项:
category_id entry_id
10 300
20 300
...
这是不正确的,因为member_id
列中有重复项:
category_id entry_id
20 300
20 400
...
我该如何查询?
如果我按照rand的顺序使用这个简单的查询,结果包含重复的行:
select c.id, e.id
from category c
inner join entry_category ec on ec.category_id = c.id
inner join entry e on e.id = ec.entry_id
group by c.id
order by rand()
性能目前不是最重要的因素,但我需要一个可靠的工作查询,上面几乎是无用的,并没有做我想要的。
编辑:除此之外,使用select distinct ...
并省略group by
时,上述查询效果不佳。这包括distinct
的重复行,只确保c.id
和e.id
的组合是唯一的。
编辑:一个解决方案我找到了,但在较大的数据集上可能会变慢:
select t1.e_id, t2.c_id
from (select e.id as e_id from entry e order by rand()) t1
inner join (select ec.entry_id as e_id, ec.category_id as c_id from entry_category ec group by e_id order by rand()) t2 on t2.e_id = t1.e_id
group by t2.c_id
order by rand()
答案 0 :(得分:1)
SELECT category_id, entity_id
FROM (
SELECT category_id,
@ce :=
(
SELECT entity_id
FROM category_entity cei
WHERE cei.category_id = ced.category_id
AND NOT FIND_IN_SET(entity_id, @r)
ORDER BY
RAND()
LIMIT 1
) AS entity_id,
(
SELECT @r := CAST(CONCAT_WS(',', @r, @ce) AS CHAR)
)
FROM (
SELECT @r := ''
) vars,
(
SELECT DISTINCT category_id
FROM category_entity
ORDER BY
RAND()
LIMIT 15
) ced
) q
WHERE entity_id IS NOT NULL
LIMIT 6
这个解决方案不是我引以为豪的一段代码,因为它依赖于MySQL
中的会话变量的黑魔法来保持递归堆栈。但是,它有效。
此外,它并非完全随机,实际上可以产生少于6
个值(如果entity_id
在各个类别中经常重复)。在这种情况下,您可以在最里面的查询中增加15
的值。
在PRIMARY KEY
上创建一个唯一索引或category_entity (category_id, entity_id)
,以便快速开展工作。
答案 1 :(得分:0)
对我来说,这样做的好方法是从每个集合中选择6个不同的值,随机抽取每个值列表(每个列表单独),然后将列表粘合在一起形成两列结果。
要随机化你得到的六个,将每种类型值的整个列表随机抽取,然后抓住前六个。