【问题标题】:Fetch fields from a table that has the same relation to another table从与另一个表具有相同关系的表中获取字段
【发布时间】:2010-10-13 17:02:58
【问题描述】:

我会尽力解释我的情况。 我正在制作一个网站,您可以在其中通过浏览标签找到主题。那里没有什么奇怪的。不过,我在一些查询方面遇到了棘手的问题。它们对你来说可能很容易,我的大脑因为做了很多工作而变得一团糟:P。

我有表格“主题”和“标签”。它们使用包含 topic_id 和 tag_id 的表 tags_topics 连接。当用户想要找到一个主题时,他们可能首先选择一个标签作为过滤依据,然后将另一个标签添加到过滤器中。然后我进行查询以获取具有两个选定标签的所有主题。他们可能还有其他标签,但他们必须选择这些标签作为过滤依据。要过滤的标签数量不同,但我们总是有一个用户选择的标签列表来过滤。 这主要是在Filtering from join-table 中回答的,我选择了多个连接解决方​​案。

现在我需要获取用户可以过滤的标签。因此,如果我们已经定义了 2 个标签的过滤器,我需要获取所有标签,但过滤器中的标签与包含过滤器中所有标签的主题相关联。这可能听起来很奇怪,所以我将举一个实际的例子:P

假设我们有三个主题:网球、健身房和高尔夫。

  • 网球有标签:运动、球、球场和球拍
  • gym 有标签:运动、训练和肌肉
  • 高尔夫有标签:运动、球、棍子和外球

    1. 用户选择标签运动,因此我们显示所有三个网球、健身房和高尔夫,并且我们显示球、球场、球拍、训练、肌肉、球杆和外部作为其他可能的过滤器。
    2. 用户现在将球添加到过滤器。过滤器现在是运动和球类,因此我们会显示网球和高尔夫主题,并使用球场、球拍、球杆和室外作为其他可能的过滤器。
    3. 用户现在将球场添加到过滤器中,因此我们将网球和球拍显示为额外的可能过滤器。

我希望我说得有道理。顺便说一句,我正在使用 MySQL。

【问题讨论】:

  • 目前还不清楚是什么让标签 1、2 和 3 的特殊之处在于“一堆其他标签”没有。为什么它们是必需的,而其余的则不是,我们怎么知道这一点?它是我们可以假设的预定义标签列表吗?
  • 您可能想提供一些表格结构并更好地解释问题。我想我得到了你想要的,但我读了 5 遍才明白。
  • @achinda99 是的,我明白了,会尝试更好地写下我的问题。 @Bill Karwin 不是真的,这次有点相反:P 我认为你认为它是重复的,因为我解释得很糟糕。我会尝试写一个更好的问题。 @chaos 我将在我的问题中描述使用场景。

标签: sql mysql join filter tags


【解决方案1】:
SELECT DISTINCT `tags`.`tag`
FROM `tags`
LEFT JOIN `tags_topics` ON `tags`.`id` = `tags_topics`.`tag_id`
LEFT JOIN `topics` ON `tags_topics`.`topic_id` = `topics`.`id`
LEFT JOIN `tags_topics` AS `tt1` ON `tt1`.`topic_id` = `topics`.`id`
LEFT JOIN `tags` AS `t1` ON `t1`.`id` = `tt1`.`tag_id`
LEFT JOIN `tags_topics` AS `tt2` ON `tt2`.`topic_id` = `topics`.`id`
LEFT JOIN `tags` AS `t2` ON `t2`.`id` = `tt2`.`tag_id`
LEFT JOIN `tags_topics` AS `tt3` ON `tt3`.`topic_id` = `topics`.`id`
LEFT JOIN `tags` AS `t3` ON `t3`.`id` = `tt3`.`tag_id`
WHERE `t1`.`tag` = 'tag1'
AND `t2`.`tag` = 'tag2'
AND `t3`.`tag` = 'tag3'
AND `tags`.`tag` NOT IN ('tag1', 'tag2', 'tag3')

【讨论】:

  • 谢谢,看起来像一个“简单”的解决方案。感觉比执行子查询更优化、性能更佳。
  • 可以,但仅限于 3 个标签。
  • 但是查询可以在应用代码中动态构建
【解决方案2】:
SELECT   topic_id
FROM     topic_tag
WHERE    tag_id = 1
      OR tag_id = 2
      OR tag_id = 3
GROUP BY topic_id
HAVING   COUNT(topic_id) = 3;

上述查询将获取所有三个tag_id 1、2和3的topic_id。然后将其用作子查询:

SELECT tag_name
FROM   tag
       INNER JOIN topic_tag
ON     tag.tag_id = topic_tag.tag_id
WHERE  topic_id  IN
                     ( SELECT  topic_id
                     FROM     topic_tag
                     WHERE    tag_id = 1
                           OR tag_id = 2
                           OR tag_id = 3
                     GROUP BY topic_id
                     HAVING   COUNT(topic_id) = 3
                     )
   AND
       (
              tag.tag_id <> 1
           OR tag.tag_id <> 2
           OR tag.tag_id <> 3
       )

我想这就是你要找的。​​p>

【讨论】:

  • 您可以进行内部联接,而不是使用 IN,但是您必须重命名某些列,我感到很懒惰。
【解决方案3】:
Select a.topic_id
  from join_table a
 where exists( select *
                 from join_table b
                where a.tag_id = b.tag_id
                  and b.topic_id = selected_topic )
 group by a.topic_id
 having count(*) = ( select count(*)
                       from join_table c
                      where c.topic_id = selected_topic )

应该给你一个主题列表,其中包含 selected_topic 的所有标签。

【讨论】:

    【解决方案4】:

    我想到的通用解决方案,但容易出现拼写错误:

      CREATE VIEW shared_tags_count AS
      SELECT topic_to_tag1.topic_id AS topic_id1, topic_to_tag2.topic_id AS topic_id2, COUNT(*) as number
        FROM topic_to_tag as topic_to_tag1
             JOIN topic_to_tag as topic_to_tag2
             ON topic_to_tag1.topic_id <> topic_to_tag2.topic_id
                 AND topic_to_tag1.tag_id = topic_to_tag2.tag_id
    GROUP BY topic_to_tag1.topic_id, topic_to_tag2.topic_id;
    
      CREATE VIEW tags_count AS
      SELECT topic_id, COUNT(*) as number
        FROM topic_to_tag
    GROUP BY topic_id
    
    CREATE VIEW related_topics AS
    SELECT shared_tags_count.topic_id1, shared_tags_count.topic_id2
      FROM shared_tags_count
           JOIN tags_count
             ON topic_id=topic_id1
                AND shared_tags_counts.number = tags_count.number
    
    CREATE VIEW related_tags AS
    SELECT related_topics.topic_id1 as topic_id, topic_to_tag.tag_id
      FROM related_topics
           JOIN topic_to_tag
           ON raleted_topics.tag_id2 = topic_to_tag.topic_id
    

    您只需查询related_tags 视图。

    顺便说一句,有趣的挑战。

    【讨论】:

    • 主要是因为表名;)我喜欢将问题分解为视图。更多代码,但在架构发生更改时更易于维护。
    • 是的,我可以看到 :) 我实际上从未使用过视图,我可能需要看看。
    猜你喜欢
    • 2018-11-11
    • 2017-04-10
    • 1970-01-01
    • 2018-10-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多