【问题标题】:How can I query related tags from a relationship table?如何从关系表中查询相关标签?
【发布时间】:2020-12-28 08:19:42
【问题描述】:

我在网站上找不到我的问题的答案。

我有 3 个表:data、tags 和 data_tag_rel。

数据

id     data
------------------------------------
1      A string of long data A.
2      A string of long data B.
3      A string of long data C.
4      A string of long data D.
5      A string of long data E.
6      A string of long data F.
7      A string of long data G.
8      A string of long data H.
n      Etc...

标签

id     tag
------------
1      gold
2      silver
3      copper
4      emerald
5      steel
6      ruby
7      carbon
8      zinc
9      mercury
n      Etc...

data_tag_rel

data     tag
------------------
1        1
1        2
2        1
3        2
4        3
5        1
5        2
5        3
6        1
7        1
8        1
8        2
8        4
8        6
n        n

如您所见,有数据和标签,还有一个关系表来确定哪些标签分配给哪些数据。这里的数据是关于矿物和岩石的。

我想要的查询是通过查看它们共同针对的数据 id 来选择与关系表中的一组更多标签相关的标签(id 和名称)。

例如,假设我分配了一个数据 id 8 与关系表中的标签 1:“gold”、2:“silver”、4:“ruby”和 6:“emerald”相关。所以现在我想查询常见的标签。如果我查询“gold”、“silver”,我希望得到返回:

A. “gold”、“silver”、“ruby”和“emerald”(包括搜索标签)。 要么 B. “ruby”和“emerald”(不包括搜索标签)。

目的是点击一个标签,看看有哪些其他标签与该点击的标签相关,它们共同相关的数据是什么,使用关系表作为指导。

到目前为止,我设法让它只搜索 1 个标签,但我无法让它适用于 2、3 或 n 个标签。

SELECT DISTINCT tags.tag FROM tags, data_tag_rel WHERE tags.id = data_tag_rel.tag AND data_tag_rel.data IN (SELECT data_tag_rel.data FROM data_tag_rel WHERE data_tag_rel.tag IN (SELECT tags.id FROM tags WHERE tags.tag IN ('gold')));

如何查询相关标签到这个数据库结构中包含 2 个或更多标签的列表?

非常感谢!

【问题讨论】:

    标签: mysql sql join mariadb subquery


    【解决方案1】:
    SELECT
      data_tag_rel.data
    FROM
      data_tag_rel
    WHERE
      data_tag_rel.tag IN ((SELECT id FROM tags WHERE tags.tag IN ('silver', 'gold')))
    GROUP BY
      data_tag_rel.data
    HAVING
      COUNT(*) = 2
    

    如果一个数据项有可能多次具有相同的标签,那会稍微改变......

    HAVING
      COUNT(DISTINCT data_tag_rel.tag) = 2
    

    讨厌的嵌套IN() 喜欢也可以换掉...

    FROM
      data_tag_rel
    INNER JOIN
      tags
        ON tags.id = data_tag_rel.tag
    WHERE
      tags.tag IN ('silver', 'gold')
    

    关键是;正常过滤,然后使用HAVING 子句确保你有两个数学,而不仅仅是一个。

    编辑:

    要明确说明如何从那里获取相关标签,只需重新加入 data_tag_rel 表...

    SELECT DISTINCT
      tags.tag
    FROM
    (
      SELECT
        data_tag_rel.data  AS id
      FROM
        data_tag_rel
      WHERE
        data_tag_rel.tag IN ((SELECT id FROM tags WHERE tags.tag IN ('silver', 'gold')))
      GROUP BY
        data_tag_rel.data
      HAVING
        COUNT(*) = 2
    )
      AS data
    INNER JOIN
      data_tag_rel
        ON data_tag_rel.data = data.id
    INNER JOIN
      tags
        ON tags.id = data_tag_rel.tag
    

    【讨论】:

    • @kintsukuroi - 您只需重新加入data_tag_rel 表... (已更新答案)
    • 最后一次编辑有效!非常感谢 Mat :D 愿上帝保佑你 :)
    【解决方案2】:

    我认为你想要的逻辑是:

    select t.*
    from tags t
    where exists (
        select 1
        from data_tag_rel dtr
        inner join data_tag_rel dtr1 on dtr1.data = dtr.data
        inner join tags t1 on t1.id = dtr1.tag
        where t1.tag in ('gold', 'silver') and dtr.tag = t.id
    )
    

    【讨论】:

    • 好的,所以这接近我需要的,但不完全是。这将返回与黄金和白银相关的所有标签 SUM,但不返回与黄金和白银相关的 INTERSECT。换句话说,这个代码是获取与黄金相关的内容,然后是与白银相关的内容,然后将这两个组合成一个大集合。我需要的是只与两者相关的标签,而不是两者的单独总和。你看到这种细微的差别了吗?真的很感谢帮助!谢谢:D
    • 由于这适用于其他用例并且可能对其他人有所帮助,我也会投票赞成,谢谢!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多