Mysql 有效地从三个表的多路联接中筛选出重复项

Mysql 有效地从三个表的多路联接中筛选出重复项,mysql,sql,Mysql,Sql,我有三个表,其中包含许多关系,如下所示: Tag +-------+---------+ | TagID | ThemeID | +-------+---------+ | t1 | th1 | +-------+---------+ | t2 | th2 | +-------+---------+ | t3 | th3 | +-------+---------+ | t4 | th1 | +-------+---------+ | t5

我有三个表,其中包含许多关系,如下所示:

Tag
+-------+---------+
| TagID | ThemeID |
+-------+---------+
| t1    | th1     |
+-------+---------+
| t2    | th2     |
+-------+---------+
| t3    | th3     |
+-------+---------+
| t4    | th1     |
+-------+---------+
| t5    | th2     |
+-------+---------+

Theme
+---------+------------+
| ThemeID | ThemeStuff |
+---------+------------+
| th1     | ts1        |
+---------+------------+
| th2     | ts2        |
+---------+------------+
| th3     | ts3        |
+---------+------------+
| th4     | ts4        |
+---------+------------+

UserTag
+-------+--------+
| TagID | UserID |
+-------+--------+
| t1    | Fred   |
+-------+--------+
| t2    | Fred   |
+-------+--------+
| t4    | Fred   |
+-------+--------+
| t4    | Frank  |
+-------+--------+
给定一个特定的UserID,我试图检索这些标记的相关主题记录,并保留一个相关的TagID值作为我如何获取该主题记录的参考

我开始采用的简单方法是:

    SELECT a.TagID, c.ThemeID, c. Themestuff FROM UserTags a, Tags b, Theme c 
        WHERE a.UserID = 'Fred' AND a.TagID = b.TagID AND b.ThemeID = c.ThemeID
问题是,如果Fred在一周内使用不同的标签访问同一主题记录,我会多次收到Fred的结果,包括同一主题记录:

+------------------------------+
| Simple Results               |
+-------+---------+------------+
| TagID | ThemeID | ThemeStuff |
+-------+---------+------------+
| t1    | th1     | ts1        |
+-------+---------+------------+
| t2    | th2     | ts2        |
+-------+---------+------------+
| t4    | th1     | ts1        |
+-------+---------+------------+
我只希望看到一个匹配的主题记录,与映射到它的标记ID之一-我不关心映射到它的特定标记ID,只要我有一个与该用户关联的标记ID

换句话说,目标结果应该是这样的:

+------------------------------+
| Target  Results              |
+-------+---------+------------+
| TagID | ThemeID | ThemeStuff |
+-------+---------+------------+
| t1    | th1     | ts1        |
+-------+---------+------------+
| t2    | th2     | ts2        |
+-------+---------+------------+ 
or
+------------------------------+
| Target  Results              |
+-------+---------+------------+
| TagID | ThemeID | ThemeStuff |
+-------+---------+------------+
| t4    | th1     | ts1        |
+-------+---------+------------+
| t2    | th2     | ts2        |
+-------+---------+------------+

我尝试在嵌套子查询上使用DISTINCT对其进行过滤,结果很快就变成了一团乱麻,仍然不太正确。我觉得一定有一个简单的解决办法,我错过了。如果您不希望主题重复,我建议您使用
存在

select th.*
from themes th
where exists (select 1
              from tags t join
                   usertags ut
                   on tu.tagid = t.tagid
              where t.themeid = th.themeid and
                    u.userid = 'Fred'
             );

这不是一个很好的答案,但仍然是一个解决方案。在浪费了一个小时试图从三个表中获得一个干净的select之后,我最终编写了一个例程来消除查询结果中的冗余


    // Sync function to remove duplicate themes from the result
    // Returns the clean list
    function reduceSet(rawOutput) {
        let lastID = null;

        for (var i = rawOutput.length-1; i >= 0; i--) {
            if (rawOutput[i].theme_id != lastID) {
                lastID = rawOutput[i].theme_id;
            } else {
                rawOutput.splice(i, 1);
            }
        }
        return rawOutput;
    }


由于生成的数据集预计不会超过100条记录,因此这可能没问题。如果有人碰巧有一个真实的答案,我仍然想知道。

请参阅“谢谢”,更新以反映反馈。感谢您的快速回复。这几乎就是我所需要的,但是它从结果中省略了一个tagid值,如上所述,我需要至少一个tagid值以及主题muff内容-我不在乎是哪一个。我只是更新了上面的问题,以确保它更清晰。是否有一种干净的方法将tagid值向上拉到外部选择?我应该运行两个嵌套查询(一个用于主题,另一个用于标记)并与结果相交吗?从未在SQL中工作过,而是在动态中学习。CM5操作系统更简单。