在一对多关系中查找“子类型”组合的频率

时间:2019-04-08 02:23:57

标签: mysql

用户可以创建“标签”。可以将标签分配给多个父母。我们正在尝试做的是找出标签组合的使用频率。我们还想知道这些组合链接到哪些父母。

我们认为如果标签具有相同的标签,则可以一起使用

Parent a, value $200
Child Tag x
Child Tag y
Child Tag z

Parent b, value $300
Child Tag x
Child Tag z

Parent c, $400
Child Tag y
Child Tag z

在上述情况下,标签y,z一起使用了2次-在父级a和父级c上。 y,z组合的总价值为600美元。

同样,标签x,z在父级a和父级b上一起使用。 x,z组合的总价值为$ 500。

我们要执行的搜索类型是:

"find combinations of any 2 tags that share a parent"
"find the total value for each combination of 2 tags that share a parent"

我很困惑如何在查询中执行此操作,并且我继续使用临时表。

1 个答案:

答案 0 :(得分:0)

首先,必须认识到这是一个多对多问题,而不是一对多问题。每个父母都有很多标签,并且每个标签都适用于许多父母。

如果您修改模型以反映此情况,则将有一个类似以下的表格:

parent_id | tag_id
------------------
a         | x
a         | y
a         | z
b         | x
b         | z
c         | y
c         | z

等等。

现在,您可以将表自身连接起来,以获得每个父级的标签组合列表:

select p1.parent_id, p1.tag_id, p2.tag_id from parent_has_tag as p1 left join parent_has_tag as p2 using(parent_id) where p2.tag_id > p1.tag_id;

>用于消除成对报告“ x,x”,并且同时返回“ x,y”和“ y,x”。

这并不是您真正想要的,但这是使您能够回答上述问题的基石。例如,“每个标签组合出现多少次?”回答如下:

SELECT count(1) AS `frequency`, GROUP_CONCAT(p1.parent_id) AS `parents`, CONCAT_WS(',', p1.tag_id, p2.tag_id) AS `pair` 
    FROM parent_has_tag AS p1 LEFT JOIN parent_has_tag AS p2 USING(parent_id) where p2.tag_id > p1.tag_id
    GROUP BY `pair`;

这会给您每个标签组合出现多少次,以及包含这些组合的父级的免费列表。但是,您下一个问题的答案只是加总父母的价值观:

SELECT count(1) AS `frequency`,
    SUM(`parents`.`value`) AS `total_value`,
    GROUP_CONCAT(p1.parent_id) AS `parents`,
    p1.tag_id AS `tag1`,
    p2.tag_id AS `tag2` 
FROM parent_has_tag AS p1 
JOIN parent_has_tag AS p2 ON p1.parent_id = p2.parent_id AND p2.tag_id > p1.tag_id
JOIN parents on p1.parent_id = parents.id
GROUP BY p1.tag_id, p2.tag_id

我认为还有优化的空间(例如,此版本比上面的版本更聪明),但这是获取所需数据的核心。

使用上述起始数据,该查询的结果如下:

+-----------+-------------+---------+------+------+
| frequency | total_value | parents | tag1 | tag2 |
+-----------+-------------+---------+------+------+
|         2 |         600 | c,a     |    x |    y |
|         2 |         500 | b,a     |    x |    z |
|         1 |         200 | a       |    y |    z |
+-----------+-------------+---------+------+------+