非常困难的mysql查询 - 两个表上的随机顺序

时间:2010-11-06 13:02:02

标签: mysql

考虑这种经典设置:

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.ide.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()

2 个答案:

答案 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个不同的值,随机抽取每个值列表(每个列表单独),然后将列表粘合在一起形成两列结果。

要随机化你得到的六个,将每种类型值的整个列表随机抽取,然后抓住前六个。