【问题描述】:

我有一个带有 Items 表的数据库,该表如下所示:

id
name
category (int)

有几十万条记录。每个 item 可以属于 7 个不同的 categories 之一,它们对应于一个 categories 表:

id
category

我想要一个从每个类别中选择 1 个随机项目的查询。解决这个问题的最佳方法是什么?我知道使用 Order By rand()LIMIT 1 进行类似的随机查询,但我从来没有做过这样的事情。

【问题讨论】:

    标签: mysql sql random sql-order-by


    【解答1】:

    此查询以随机顺序返回所有加入类别的项目:

    SELECT
    c.id AS cid, c.category, i.id AS iid, i.name
    FROM categories c
    INNER JOIN items i ON c.id = i.category
    ORDER BY RAND()
    

    要将每个类别限制为一个,请将查询包装在 partial GROUP BY 中:

    SELECT * FROM (
        SELECT
        c.id AS cid, c.category, i.id AS iid, i.name
        FROM categories c
        INNER JOIN items i ON c.id = i.category
        ORDER BY RAND()
    ) AS shuffled_items
    GROUP BY cid
    

    请注意,当查询同时具有 GROUP BYORDER BY 子句时,会在排序之前执行分组。这就是我使用两个查询的原因:第一个对结果进行排序,第二个对结果进行分组。

    我知道这个查询不会赢得任何比赛。我愿意接受建议。

    【问题讨论】:

    • 经过一些更正后,上述查询有效: SELECT * FROM ( SELECT c.id as cid, c.category, i.id, i.name FROM categories c INNER JOIN Items i ON c .id = i.category ORDER BY RAND() ) AS ShuffleledItems GROUP BY ShffeledItems.cid
    • 嗯,这个修改后的查询为我返回了大约 1500 行
    • @SalmanA 是的,我不知道该说什么。我正在我的数据库上尝试它,它返回大约 1500 行,而不是 7。
    • 这很奇怪,因为这里是按类别 id 分组的,所以如果你得到大约 1500 行,你就有 1500 个类别...
    • @rzymek 啊没关系,你是对的。我的表中的语法略有不同,这导致了问题!非常感谢!
    【解答2】:

    这是一个简单的解决方案。假设你有这张桌子。

    id  name    category
    1   A       1
    2   B       1
    3   C       1
    4   D       2
    5   E       2
    6   F       2
    7   G       3
    8   H       3
    9   I       3
    

    使用这个查询

    select
      c.id,
      c.category,
      (select name from category where category = c.category   group by id order by rand() limit 1) as CatName
    from category as c
    group by category
    

    【问题讨论】:

    • 这个我无法理解,因为似乎没有参考 items 表,只有 categories
    • @dtj 我的查询中没有关键字项目,那么您有什么困惑?我已经给你举了一个例子,你可以在它之后自己锻炼。
    • 您确定 GROUP BYRAND() 会一起工作,为每个组随机分配一个吗?因为我怀疑它。
    【解答3】:

    试试这个

    SELECT id, name, category from Items where
    ( 
     select count(*) from Items i where i.category = Items.category 
     GROUP BY i.category ORDER BY rand()
    ) <= 1
    

    参考号:http://www.xaprb.com/blog/2006/12/07/how-to-select-the-firstleastmax-row-per-group-in-sql/

    【问题讨论】:

    • 这一项,报错子查询返回多于1行
    【解答4】:

    在最终选择之前更改原始表的顺序(随机顺序):

    select * from 
      (select category, id, name from categories order by rand()) as tab 
      group by 1
    

    【问题讨论】:

    • 请用一些 cmets 更新您的答案以及它是如何回答问题的。
    【解答5】:

    请注意:在以下示例中,我假设您的表名为“items”而不是“Items”,因为您还说另一个表名为“categories”(第二个表名未大写)。

    你想要做的 SQL 大概是:

    `SELECT items.id AS item_id,
    items.name AS item_name,
    items.category AS item_category_id,
    categories.id AS category_id,
    categories.category AS category_name
    FROM items, category
    WHERE items.category = categories.id
    ORDER BY rand()
    LIMIT 1`
    

    【问题讨论】:

    • 这个查询只返回一行。没有 LIMIT 1 - 每个类别的所有项目...
    • @ryzmek,是的,没错。巧合的是,这也是OP所要求的。 OP 说,我引用:“我想要一个从每个类别中选择 1 个随机项目的查询”
    • 在我看来,作者希望查询返回 7 行,每个类别一个 rand 项。
    • 抱歉,如果不清楚。查询应返回 7 行 -- 每个类别对应 1 行
    • 这个查询只返回一行