2013-12-08 4 views
2

프로필 설문지에서 온 인구 통계에 대한 사용자 정의 필드를 저장하기위한 xml 열이 포함 된 사용자 테이블이 있습니다. 사용자의다른 XML 컬럼에 대한 쿼리

인구학 시료 입력 :

<demographics> 
     <question_1>answer_1</question_1> 
     <question_2>answer_2</question_2> 
     <question_3>answer_3</question_3> 
    </demographics> 

할당 테이블 다시 프로필 설문 기반으로 사용자의 자격에 대한 또 다른 XML 컬럼을 갖는다.

<Eligibility> 
    <Expression> 
    <Question>question_1</Question> 
    <Answer>answer_1</Answer> 
    </Expression> 
    <Expression> 
    <Question>question_3</Question> 
    <Answer>answer_3</Answer> 
    </Expression> 
</Eligibility> 

표에 정의 된 xml 적합성 기준에 따라 사용자의 인구 통계와 일치하는 모든 할당을 찾아야합니다. 자격 기준 간의 운영자는 'AND'이어야합니다. 다음은 내가 작성한 질의입니다.

SELECT * 
    FROM Assignments AS a 
    WHERE Eligibility.exist('/Eligibility/Expression[Question= 1 and Answer=1]') = 1 
    AND Eligibility.exist('/Eligibility/Expression[Question= 2 and Answer=2]') = 1 

두 개의 할당 A1과 A2가 있다고 가정합니다. A1은 Question1 = Answer1이고 A2는 Question2 = Answer2라는 기준을 가지고 있습니다. 두 과제 모두 사용자의 자격 요건을 충족시킵니다. 그러나 위의 쿼리는 적격성 기준 사이에 'AND'가 있기 때문에 두 할당 중 하나를 반환하지 않습니다.

도움을 주시면 감사하겠습니다.

답변

4

실제로는 XML 데이터를 사용하는 relational division 쿼리입니다.

코드의 주석은 쿼리의 각 부분에서 일어나는 일을 설명합니다.

-- A users demographics 
declare @UserDem xml = ' 
<demographics> 
    <question_1>answer_1</question_1> 
    <question_2>answer_2</question_2> 
    <question_3>answer_3</question_3> 
</demographics>'; 

-- Get ID for the assignment 
select A.ID 
from Assignments as A 
    -- Calculate the number of Expression there are in each assignment 
    cross apply (select A.Eligibility.value('count(/Eligibility/Expression)', 'int')) as C(ECount) 
    -- Shred on Expression 
    cross apply A.Eligibility.nodes('/Eligibility/Expression') as E(X) 
    -- Join to demographics on question and answer 
    inner join @UserDem.nodes('demographics/*') as D(X) 
    on D.X.value('local-name(.)[1]', 'nvarchar(100)') = E.X.value('(Question/text())[1]', 'nvarchar(100)') and 
     D.X.value('text()[1]', 'nvarchar(100)') = E.X.value('(Answer/text())[1]', 'nvarchar(100)') 
-- Group on ID and get the Assignments that are fully covered by the demographic 
group by A.ID, C.ECount 
having count(*) = C.ECount; 

SQL Fiddle

관련 문제