简体   繁体   English

在MySQL中选择多对多关系

[英]Select in a many-to-many relationship in MySQL

I have two tables in a MySQL database, Locations and Tags, and a third table LocationsTagsAssoc which associates the two tables and treats them as a many-to-many relationship. 我在MySQL数据库中有两个表,Locations和Tags,以及第三个表LocationsTagsAssoc,它们将两个表关联起来并将它们视为多对多关系。

Table structure is as follows: 表结构如下:

Locations
---------
ID int (Primary Key)
Name varchar(128)

LocationsTagsAssoc
------------------
ID int (Primary Key)
LocationID int (Foreign Key)
TagID int (Foreign Key)

Tags
----
ID int (Primary Key)
Name varchar(128)

So each location can be tagged with multiple tagwords, and each tagword can be tagged to multiple locations. 因此,每个位置都可以使用多个标记字进行标记,并且每个标记字都可以标记为多个位置。

What I want to do is select only Locations which are tagged with all of the tag names supplied . 我想要做的是只选择标有所有提供的标签名称的位置 For example: 例如:

I want all locations which are tagged with both "trees" and "swings". 我想要所有标有“树”和“秋千”的地点。 Location "Park" should be selected, but location "Forest" should not. 应选择位置“公园”,但不应选择位置“森林”。

Any insight would be appreciated. 任何见解将不胜感激。 Thanks! 谢谢!

There are two ways to do this. 有两种方法可以做到这一点。 I prefer the first way, which is to self-join for each tag: 我更喜欢第一种方式,即为每个标签自我加入:

SELECT l.*
FROM Locations l
JOIN LocationsTagsAssoc a1 ON a1.LocationID = l.ID
JOIN Tags t1 ON a1.TagID = t1.ID AND t1.Name = ?
JOIN LocationsTagsAssoc a2 ON a2.LocationID = l.ID
JOIN Tags t2 ON a2.TagID = t2.ID AND t2.Name = ?
JOIN LocationsTagsAssoc a3 ON a3.LocationID = l.ID
JOIN Tags t3 ON a3.TagID = t3.ID AND t3.Name = ?;

The other way also works, but using GROUP BY in MySQL tends to incur a temporary table and performance is slow: 另一种方式也有效,但在MySQL中使用GROUP BY往往会产生临时表并且性能很慢:

SELECT l.*
FROM Locations l
JOIN LocationsTagsAssoc a ON a.LocationID = l.ID
JOIN Tags t ON a.TagID = t.ID
WHERE t.Name IN (?, ?, ?)
GROUP BY l.ID
HAVING COUNT(*) = 3;

You need locations where there doesn't exist a given tag that doesn't appear in the LocationsTagsAssoc table with the location. 您需要的位置不存在LocationsTagsAssoc表中未显示给定标记的位置。

You can specify the given tags with IN () as in the following, or by joining onto another table containing them. 您可以使用IN()指定给定标记,如下所示,或者通过连接到包含它们的另一个表。

Ie

SELECT l.*
FROM Locations AS l
WHERE NOT EXISTS (
    SELECT NULL FROM Tags AS t
    WHERE NOT EXISTS (
        SELECT NULL FROM LocationsTagsAssoc AS lt
        WHERE lt.LocationId = l.ID
            AND lt.TagID = t.ID
    )
        AND t.ID IN (1, 2, 3,...)
)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM