2010-06-08 2 views
3

MySQL 데이터베이스에 Locations 및 Tags라는 두 개의 테이블과 두 개의 테이블을 연결하고 many-to-many 관계로 취급하는 세 번째 테이블 LocationsTagsAssoc이 있습니다. MySQL에서 many-to-many 관계로 선택

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) 

는 각각의 위치에 여러 tagwords로 태그 될 수 있으며, 각 tagword 여러 위치로 태그 될 수있다 : 다음

테이블 구조이다. 내가 원하는 무엇

는 공급 와 태그 이름의 모든 태그 만 위치를 선택합니다. 예 :

'나무'와 '스윙'으로 태그가 지정된 모든 위치를 원합니다. 위치 "공원"을 선택해야하지만 위치 "숲"은 선택하면 안됩니다.

어떤 통찰력도 인정 될 것입니다. 감사!

답변

6

두 가지 방법이 있습니다.

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 = ?; 

다른 방법도 작동하지만, 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; 
+0

감사합니다. 이것은 이해가되고 잘 작동합니다. 두 쿼리 모두 5 개의 태그 쿼리에 대해 동일한 속도입니다. 그 이상은 테스트하지 않았습니다. 우수 답변 - 감사합니다. –

+0

경험에 비추어 볼 때, 후자의 접근 방식이 (나에게는 어쨌든) 좋지만, 큰 테이블에서는 첫 번째 접근 방식이 훨씬 더 효율적일 것입니다. –

+1

@NickF, 예, self-join 메소드가 훨씬 더 나은 성능을 가지고 있음을 발견했습니다. 내 프레젠테이션의 결과보기 [SQL Query Patterns, Optimized] (http://www.slideshare.net/billkarwin/sql-query-patterns-optimized) –

0

위치가있는 LocationsTagsAssoc 테이블에 표시되지 않는 특정 태그가없는 위치가 필요합니다.

다음과 같이 주어진 태그를 IN()으로 지정하거나 태그를 포함하는 다른 테이블에 조인하여 지정할 수 있습니다.

e.e.

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,...) 
) 
관련 문제