2013-08-11 3 views
1

나는 다음과 같은 테이블이 있습니다매칭 세트 상호 참조

  • 책 : 태그 목록 (소설, 전기 등)
  • xrefbookstags : 책
  • 태그 목록을 : 상호 참조 테이블 (책 여러 태그가) 태그 세트를 주어 내가 뭘하고 싶은

그 태그 세트와 정확히에 맞는 책을 찾을 수 있습니다. 다음은 내가 시도한 것입니다.

SELECT B.name, B.author, B.id, B.finished, B.manual 
    FROM books B INNER JOIN xrefbookstags XRBT 
     ON XRBT.idBooks=B.id JOIN tags T 
     ON XRBT.idTags=T.id 
    WHERE T.name IN ('novel','biography') 

이렇게하면 집합이 동일하지 않습니다. 그래서 나는 세트 내의 태그의 수를 세고 세트의 크기와 일치시켜야한다고 생각했습니다.

SELECT B.name, B.author, B.id, B.finished, B.manual 
    FROM books B INNER JOIN xrefbookstags XRBT 
     ON XRBT.idBooks=B.id JOIN tags T 
     ON XRBT.idTags=T.id 
    WHERE T.name IN ('novel','biography') AND count(T.id)=2 

는하지만이 실패합니다. 그래서 여기 내 질문이 온다 : 나는이 상호 참조 환경에서 세트를 일치시킬 수 있을까?

답변

1

당신은 EXISTSNOT EXISTS을 결합 할 수 있습니다 :

SELECT B.name, B.author, B.id, B.finished, B.manual 
FROM books B 
WHERE EXISTS(
    SELECT 1 FROM xrefbookstags XRBT 
    INNER JOIN Tags T ON XRBT.idTags=T.id 
    WHERE XRBT.idBooks=B.id 
    AND T.name = 'novel' 
) 
AND EXISTS(
    SELECT 1 FROM xrefbookstags XRBT 
    INNER JOIN Tags T ON XRBT.idTags=T.id 
    WHERE XRBT.idBooks=B.id 
    AND T.name = 'biography' 
) 
AND NOT EXISTS(
    SELECT 1 FROM xrefbookstags XRBT 
    INNER JOIN Tags T ON XRBT.idTags=T.id 
    WHERE XRBT.idBooks=B.id 
    AND T.name NOT IN ('novel','biography') 
) 
+0

실제로 입력 태그를 제어 할 수는 없지만 변수가 포함되어 있습니다. 여기'('소설', '전기')는 단지 예일뿐입니다. COUNT (T.id)를 출력하고 끝에 GROUP BY T.id를 추가 할 수 있습니다. 그러나이 방법은 SQL 출력을 후 처리합니다. SQL 만 사용하고 압축 된 요청을 사용하여 모든 결과를 얻고 싶습니다. – vanna

0

이것은 "설정에서-세트"쿼리의 예입니다. 가장 일반적인 방법은 group by을 사용하고 로직을 having 절에 넣는 것입니다. 귀하의 경우 :

SELECT B.name, B.author, B.id, B.finished, B.manual 
FROM books B INNER JOIN 
    xrefbookstags XRBT 
    ON XRBT.idBooks = B.id JOIN 
    tags T 
    ON XRBT.idTags = T.id 
group by B.name, B.author, B.id, B.finished, B.manual 
having sum(case when t.name = 'novel' then 1 else 0 end) > 0 and 
     sum(case when t.name = 'biography' then 1 else 0 end) > 0 and 
     sum(case when t.name not in ('novel', 'biography') then 1 else 0 end) = 0; 

논리는 다음과 같습니다. 첫 번째 절은 하나 이상의 태그가 'novel' 일 때 true입니다. 두 번째 절은 적어도 하나의 절이 'biography'이고 다른 태그가없는 경우 세 번째 절이 참일 때 true입니다.

이것은 쉽게 일반화 할 수 있습니다. 당신이 책을 원한다면

having sum(case when t.name = 'novel' then 1 else 0 end) > 0 or 
     sum(case when t.name = 'biography' then 1 else 0 end) > 0; 

: 당신은 하나 또는 다른 있었다 책을 원한다면

having sum(case when t.name = 'novel' then 1 else 0 end) > 0 and 
     sum(case when t.name = 'biography' then 1 else 0 end) > 0; 

:이 두 태그를했지만, 다른 사람을 가질 수 책을 원한다면, 단지 세 번째 절을 생략 그 한 두 플러스 '역사', 당신은 그것을 추가 할 것입니다 : 당신이를 원하지만 요리에 대한 경우,

having sum(case when t.name = 'novel' then 1 else 0 end) > 0 and 
     sum(case when t.name = 'biography' then 1 else 0 end) > 0 and 
     sum(case when t.name = 'historical' then 1 else 0 end) > 0; 

그리고 :

having sum(case when t.name = 'novel' then 1 else 0 end) > 0 and 
     sum(case when t.name = 'biography' then 1 else 0 end) > 0 and 
     sum(case when t.name = 'historical' then 1 else 0 end) > 0 and 
     sum(case when t.name = 'cooking' then 1 else 0 end) = 0; 

편집 :

당신이 일치 할 태그의 쉼표로 구분 된 목록이있는 경우

은, 당신은 할 수 있습니다 :

having sum(case when ','[email protected]+',' not like '%,'+t.name+',%' then 1 else 0 end) = 0 and 
     count(distinct t.name) = 1 + len(@list) - len(replace(@list, ',', '')) 

첫 번째 절은 모든 태그는 목록에있는 것을 말한다. 두 번째는 태그의 길이가 목록의 길이라는 것입니다.

이것은 본질적으로 의사 코드입니다. 서로 다른 데이터베이스는 len() 함수의 서로 다른 이름과 함께 문자열을 연결하는 다양한 방법과 변수 값을 표현하는 다양한 방법을 제공합니다. 그러나 그 의도는 분명해야합니다.

+0

@Tim Schmelter와 같은 말처럼, 태그를 포함하는 변수가 있으므로 크기가 아무 것도 될 수 없습니다. 나는 SQL을 생성 할 수 있었지만 그것을 유지하고 싶습니다. SQL에 내장 된 기능이 있나요? – vanna

2

당신은

는) 그 책, b)에 필요한 태그 목록에없는 책에 대한 태그가 없기 때문이다 실종 더 필요한 태그가 없습니다있는 그 책을 원한다.

해당 태그 이름의 id를 테이블 (여기서는 즉시 수행)에 넣고 이렇게합니다. (SQL Fiddle 또는 CREATE TABLE/INSERT 샘플 데이터가 없으므로 모든 세부 사항을 검사하지 않았습니다.)

WITH TagIDs(id) AS (--required tag ids 
    SELECT id 
    FROM tags 
    WHERE name in ('novel', 'biography') 
) 

    SELECT B.name, B.author, B.id, B.finished, B.manual --select those books 
    FROM books B 

    WHERE --a) 
    NOT EXISTS ( -- there is no 
    SELECT * FROM TagIDs -- required tag 
    WHERE TagIDs.id NOT IN (-- that's missing 
     SELECT XRBT.idTags FROM xrefbookstags XRBT -- from the list of tags 
     WHERE XRBT.idBooks=B.id -- for this particular book 
    ) 
) 
    AND --b) 
    NOT EXISTS (-- there is no 
    SELECT * FROM xrefbookstags XRBT --tag 
    WHERE XRBT.idBooks=B.id --for this particular book 
    AND XRBT.idTags NOT IN (--that's missing 
     SELECT id FROM TagIDs --from the list of required tags 
    ) 
)