2012-05-15 2 views
1

온라인 라이브러리 검색 엔진에서 작업하고 있지만 여기에 붙어 있습니다. 태그를 검색 할 때 OR 검색 (예 : "tag1"OR "tag2"가 포함 된 책)은 정상적으로 작동하지만 AND 검색을 사용하면 문제가 발생합니다.MySQL이 모든 태그가있는 항목을 검색했습니다.

나는이에 사용하는 테이블 (및 열)입니다 : 다른 검색 옵션의 무리가 EN/사용자가 사용할 수 있기 때문에

books | book_id, other_info 
tagmap | map_id, book_id, tag_id 
tags | tag_id, tag_text 

쿼리는 PHP에 의해 생성됩니다. 태그 "이 tag1"AND "이 tag2"책을 검색 할 때, 다음 쿼리가 생성됩니다

SELECT DISTINCT b.book_id, b.other_info 
FROM books b, tagmap tm, tags t 
WHERE b.book_id = "NA" 
OR ((t.tag_text IN ("tag1", "tag2")) 
     AND tm.tag_id = t.tag_id 
     AND b.book_id = tm.book_id) 
HAVING COUNT(tm.book_id)=2 

를 Where 추가 매개 변수에 중독 될 수 있도록 (어떤 결과를 제공하지 않는 것은)이 라인 쿼리를보다 쉽게 나는 이것이 훨씬 더 멋지게 처리 될 수 있다는 것을 알고 있지만, 지금은 상관 없습니다.

동일한 검색어이지만 HAVING COUNT 행이없는 OR 검색을 수행하면 데이터베이스에 두 태그 중 하나가있는 두 권의 책이 반환되지만 두 태그가 모두있는 데이터베이스에서 한 도서를 검색 할 때, 아무것도 반환하지 않습니다.

검색어가 잘못되었습니다. 이것이/할 방법이 아닌가? 나는 무엇을 간과하고 있는가?

감사합니다.

편집은 : 요청에 따라, 책에 관한 각 테이블의 데이터가 반환해야한다 :

books table: 
book_id  110 

tagmap table: 
book_id  110 110 
tag_id  15  16 

tags table: 
tag_id  15  16 
tag_text tag1 tag2 

해결 : 내가해야 할 일을했을 모든이었다 포함

GROUP BY b.book_id 

전 HAVING COUNT 행. 그처럼 간단합니다. taz가 제공 한 답은 특히 검색 쿼리를 최적화하려는 경우에 유용합니다.

+0

당신은 테이블에서 데이터를 게시 할 수해야 표시하고 있습니까? – taz

+0

또한 쉼표로 구분 된 테이블 이름 목록 대신 내부 조인을 사용해야합니다. 실수를하기 쉽고 때로는리스트 문법으로 큰 데카르트 곱을 계산하는 것이 쉽습니다! – taz

+0

표시되는 유일한 정보는 책에 대한 기타 정보입니다.이 정보는 other_info 열에 요약되어 있습니다. 또는 쿼리 실행과 관련된 모든 데이터를 의미합니까? – Fang

답변

1

FROM 절의 쉼표로 구분 된 테이블 목록은 내부 조인과 같은 기능을하므로 쿼리는 tagmaps 테이블과 동일한 태그 ID를 가진 tags 테이블의 행을 모두 선택합니다. 도서 ID가 동일한 books 테이블과 tagmaps 테이블의 행 수 HAVING 절은 동일한 서적 ID로 결과 세트에서 두 행이 리턴되도록 요구합니다. 책 테이블에는 지정된 책 ID (책 ID가 책 테이블의 기본 키라고 가정)가있는 행이 하나만있을 수 있으므로이 조건을 결코 충족시키지 못합니다.

원하는 것은 서적 테이블이없는 조인입니다. OR 절의 결과에 두 번 나타나는 동일한 책 ID를 찾고 있습니다. (나는 믿습니다.) 그래서 당신은 그 책 테이블에 같은 책 ID를 가질 수 없기 때문에 그 결과로 책 테이블에 참여하고 싶지 않습니다. 결과는 두 번 이상 나타납니다.

편집 : 개념적으로, 당신은 근본적으로 두 가지 다른 것들을 결합합니다. 같은 책에 대한 태그와 태그 맵을 찾고 있으며 각 책에서 책 정보를 얻고 있습니다. 따라서 실제로 tagmaps 테이블에서 동일한 book ID의 모든 인스턴스에 대해 중복 된 other_info 데이터를 가져온 다음 distinct 절을 사용하여 중복 데이터를 한 행으로 줄입니다. 원하는 모든 것은 book ID 및 other_info입니다. 이 작업을 수행하려면 두 개의 쿼리 또는 하위 쿼리를 사용하는 것이 좋습니다. 다른 [더 나은] 방법이있을 수 있습니다. 나는 그걸 알아 내기 위해 놀아야 만 할 것입니다.우선 들어

, 다른 책 정보를 선택

SELECT DISTINCT tm.book_id, b.other_info 
FROM tagmap tm inner join tags t 
    on tm.tag_id = t.tag_id 
    left join books b 
    on tm.book_id = b.book_id 
HAVING count(tm.book_id) = 2 
+0

나는 이해한다고 생각한다. 그러나 "books b"조인을 제거하고 모든 b.book_id를 tm.book_id로 바꾸고 마지막 AND 절을 제거한 후에도 여전히 결과를 얻지 못합니다. 이상한 일은 : 나는 또한 항목에 속한 두 개의 다른 태그를 사용하여 시도했지만 잘못된 쿼리를 사용하여도 그 태그는 정상적으로 작동했습니다. 다른 항목/태그는 여전히 작동하지 않습니다. 그게 뭐죠? – Fang

+0

문제에 대한 해결책을 찾았습니다. (잠깐 후에 질문에 추가 할 예정입니다.)하지만 필자가 제안한 것과 유사한 쿼리를 확실히 조사 할 것입니다. 로마로 이어지는 도로가 여러 개 있다고 생각합니다. 도와 주셔서 정말 감사합니다! – Fang

+0

@Fan 문제 없습니다. 미안해, 내가 너에게 빨리 돌아갈 시간이 없어. 'GROUP BY'는 또한 당신이 원하는 것보다 더 많은 데이터를 가져올지라도 당신의 목적을 위해 작동해야합니다. 여전히 결과가 나타나지 않는다면 쉼표 목록을 사용하고 올바른 ID 필드를 사용하고 있는지 확인하는 대신 명시 적으로 JOIN 절이있는 테이블을 조인하고 있는지 확인하는 것이 좋습니다. SQL을 실제로 테스트하지 않고 제공 한 정보를 바탕으로 생각해 봅시다. 동일한 tagID를 가진 모든 tagmaps & tags를 가져온 다음 각 tagID와 동일한 bookID를 가진 모든 책을 가져옵니다. – taz

1
SELECT book_id FROM tagmap JOIN tags ON (tag_id) WHERE tag_text = "tag1" 
INTERSECT 
SELECT book_id FROM tagmap JOIN tags ON (tag_id) WHERE tag_text = "tag2" 

랩 하위 쿼리로이 모든 일을하려고이 필요합니다

SELECT book_id, other_info FROM books WHERE book_id IN 
(
    ... 
) 
+0

MySQL은 INTERSECT 근처에 오류가 있음을 알립니다. – Fang

관련 문제