Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/mysql/68.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
mysql根据另一个联接表的结果查询联接表_Mysql - Fatal编程技术网

mysql根据另一个联接表的结果查询联接表

mysql根据另一个联接表的结果查询联接表,mysql,Mysql,我有五张桌子。标签,流,流标签,帖子,帖子标签。streams_标记和posts_标记只是标记、streams和posts的联接表 我想从posts表中选择所有posts,这些posts表包含通过streams\u tags表与流关联的所有标记。例如,如果一个流有相关的标签cat,dog,那么所有带有相关标签cat,dog的帖子都应该返回。不管帖子中是否有更多的标签而不是猫,狗,只要它包含猫,狗标签就行 标签: id |名称 溪流: id |名称 streams\u标签: id |流|标记| i

我有五张桌子。标签,流,流标签,帖子,帖子标签。streams_标记和posts_标记只是标记、streams和posts的联接表

我想从posts表中选择所有posts,这些posts表包含通过streams\u tags表与流关联的所有标记。例如,如果一个流有相关的标签cat,dog,那么所有带有相关标签cat,dog的帖子都应该返回。不管帖子中是否有更多的标签而不是猫,狗,只要它包含猫,狗标签就行

标签: id |名称

溪流: id |名称

streams\u标签: id |流|标记| id

posts:id | name

posts_标签:id | post_id | tag_id

此查询应返回指定的结果集:

SELECT p.id
     , p.name
  FROM posts p
 WHERE NOT EXISTS
       ( SELECT 1
           FROM streams_tags st
          WHERE st.stream_id = 201   /* <-- specified stream_id value */
            AND NOT EXISTS
                ( SELECT 1
                    FROM posts_tags pt
                   WHERE pt.tag_id = st.tag_id
                     AND pt.post_id = p.id
                 )
        )
当我们运行该查询来检查posts.id=67时,我们不会返回任何行。这意味着posts.id 67匹配指定流的所有标记

当我们再次运行它时,指定posts.id=68,我们将返回一行。我们返回的行是post_标记中缺少的streams_tag.tag_id值

因此,如果我们对每个post\u id运行这个查询,并检查这个查询是否返回行,我们就可以知道哪些post与指定的stream\u id的所有streams\u tags.tag\u id相匹配。。。为每个帖子id运行此查询

另一种完全不同的方法是获取帖子上匹配标记的数量,并将其与流上的标记数量进行比较

SELECT p.id
     , p.name
     , sc.st_count AS st_count
  FROM ( SELECT stc.stream_id
              , COUNT(DISTINCT stc.tag_id) AS st_count
           FROM streams_tags stc
          WHERE stc.stream_id = 201
          GROUP BY stc.stream_id
       ) sc
 CROSS
  JOIN posts p
  LEFT
  JOIN posts_tags pt
    ON pt.post_id = p.id
  LEFT
  JOIN streams_tags st
    ON st.tag_id = pt.tag_id
   AND st.stream_id = sc.stream_id
 GROUP
    BY p.id
     , p.name
HAVING COUNT(DISTINCT st.tag_id) >= sc.st_count
注意:要从HAVING子句中可用的特定stream_id的streams_标记中获取标记计数,必须将其包括在查询的SELECT列表中。另一种方法是将该子查询下移到HAVING子句,然后在查询中重复指定的stream_id值两次

SELECT p.id
     , p.name
  FROM posts p
  LEFT
  JOIN posts_tags pt
    ON pt.post_id = p.id
  LEFT
  JOIN streams_tags st
    ON st.tag_id = pt.tag_id
   AND st.stream_id = 201  /* <- specified stream_id */
 GROUP
    BY p.id
     , p.name
HAVING COUNT(DISTINCT st.tag_id) >=
       ( SELECT COUNT(DISTINCT stc.tag_id) AS st_count
           FROM streams_tags stc
          WHERE stc.stream_id = 201 /* <- specified stream_id */ 
       )

你试过什么?您需要使用内部联接来联接表。这就是你需要帮助的地方还是更微妙的地方?@Melanie-我已经尝试了太多东西,想在这里发布。我不相信我被困在连接上了。我被卡住的地方是能够确定一篇文章是否包含与流关联的所有标记。@Tony:欢迎来到Stackoverflow!这是一个棘手的问题,匹配所有标记,而不仅仅是任何标记。但是使用标准的MySQL语法是可以做到这一点的。哇,这非常好用。感谢您的详细解释和多种解决方案。我学到了很多。我真的很担心这件事,你帮我节省了很多时间和工作。这是我第一篇关于StackOverflow的帖子,现在我更喜欢它了。谢谢。@Tony:欢迎来到StackOverflow!仅供参考-这些查询在小集合上的性能将是合理的;但是,对于庞大的集合,即posts表中的数百万行,这两个查询可能会变成真正的资源消耗。POST_标记和streams_标记表上的适当覆盖索引对于最佳性能是必要的。
SELECT p.id
     , p.name
  FROM posts p
  LEFT
  JOIN posts_tags pt
    ON pt.post_id = p.id
  LEFT
  JOIN streams_tags st
    ON st.tag_id = pt.tag_id
   AND st.stream_id = 201  /* <- specified stream_id */
 GROUP
    BY p.id
     , p.name
HAVING COUNT(DISTINCT st.tag_id) >=
       ( SELECT COUNT(DISTINCT stc.tag_id) AS st_count
           FROM streams_tags stc
          WHERE stc.stream_id = 201 /* <- specified stream_id */ 
       )