3

我有以下表格:

TABLE product
id int(11)
title varchar(400)

TABLE tag
id int(11)
text varchar(100)

TABLE product_tag_map
product_id int(11)
tag_id int(11)

PRODUCT_TAG_MAP 将标签映射到产品。系统中标签的分布不正常,即有些标签的产品比其他标签多得多。

我正在尝试编写一个将获取 25 个随机产品的 SQL:每个标签 5 个产品,用于 5 个标签(所以这是 5x5 = 25)。

在这里找到了答案:How can I get an even distribution using WHERE id IN(1,2,3,4)

但这不会产生随机产品——它总是为每个标签获取相同的产品。

这是我的SQL:

SET @last_tag = 0;
SET @count_tag = 0;

SELECT DISTINCT id FROM (
SELECT
  product.*,
  @count_tag := IF(@last_tag = product_tag_map.tag_id, @count_tag, 0) + 1 AS tag_row_number,
  @last_tag := product_tag_map.tag_id
FROM product
  LEFT JOIN product_tag_map ON (product_tag_map.product_id=product.id)
WHERE
  product_tag_map.tag_id IN (245,255,259,281,296)
) AS subquery WHERE tag_row_number <= 5;

如何使它返回每个标签的随机产品?

任何帮助将非常感激!谢谢。

4

2 回答 2

2

这个查询有很多技巧:

  1. 添加嵌套级别以在子查询中使用 LIMIT:mySQL 子查询限制
  2. 为 MySQL 添加 row_number 功能:How to select the first/least/max row per group in SQL

最终结果是很多子查询:

SELECT tag.Name, t0.Id as MapId
FROM
(
    SELECT * 
         , @num := if(@type = tag_id, @num + 1, 1) as row_number
         , @type := tag_id as dummy
    FROM (
        SELECT *
        FROM map m
        WHERE tag_id in
        (
            SELECT *
            FROM
            (
                SELECT id
                FROM tag
                ORDER BY RAND() LIMIT 5
            ) t
        )
     ORDER BY tag_id, RAND()  
  ) mainTable
  , (SELECT @num:=0) foo
  , (SELECT @type:=0) foo2
) t0 
    INNER JOIN tag
        ON t0.tag_id = tag.id
WHERE row_number <= 5

SQL小提琴

这个想法是选择前 5 个随机标签。这并不难,只是一个简单的ORDER BY RAND() LIMIT 5.

然后棘手的部分是太模拟 a ROW_NUMBER() OVER(PARTITION BY tag_id, RAND()),因为随机排列每个项目,但按标签分区正是您所需要的。所以你声明变量并按照查询显示的那样做。

最后,过滤 row_number,你就有了 25 个随机项目!

于 2013-04-25T14:51:16.427 回答
0

我还想提供“蛮力”方法。这适用于大多数数据库(尽管该rand()函数可能被命名为其他名称)。

select content_item_id from content_item where tag_id = 245 order by RAND() limit 5
union all
select content_item_id from content_item where tag_id = 255 order by RAND() limit 5
union all
select content_item_id from content_item where tag_id = 259 order by RAND() limit 5
union all
select content_item_id from content_item where tag_id = 281 order by RAND() limit 5
union all
select content_item_id from content_item where tag_id = 206 order by RAND() limit 5

如果您在content_item(tag_id).

于 2013-04-25T15:37:59.687 回答