2016-11-28 6 views
1

내가 XML 열을 구문 분석을 시도하고 노드의 여러 하위 노드를 통해 두 가지SQL 서버 2012 : 다음 하위 노드 중 하나뿐만 아니라 CONCAT 모든 하위 노드를 선택 XML 파싱

  • 으로 반복을하고 선택하는 것을 시도하고있다 하나의 노드는 1/0 플래그 값을 기반으로합니다. 그러나

    IsActive PID PublicWorkPhone location 
    -------- ----- --------------- -------- 
    1  111 (101)111-1111 NULL 
    1  222 NULL   NULL 
    1  333 NULL   NY 
    

    :이 얻을

    create table #temp (XMLData xml) 
    
    insert into #temp (XMLData) 
    values (' 
    <Report_Data> 
        <Report_Entry> 
        <IsActive>1</IsActive> 
        <PID>111</PID> 
        <Languages> 
         <Language>German</Language> 
         <speak>Y</speak> 
         <read>Y</read> 
         <write>Y</write> 
        </Languages> 
        <Languages> 
         <Language>Spanish</Language> 
         <speak>Y</speak> 
         <read>N</read> 
         <write>N</write> 
        </Languages> 
        <phone> 
         <PhoneNumber>(101)111-1111</PhoneNumber> 
         <PhoneType>Work</PhoneType> 
         <IsPrimary>1</IsPrimary> 
        </phone> 
        <phone> 
         <PhoneNumber>(101)111-2222</PhoneNumber> 
         <PhoneType>Mobile</PhoneType> 
         <IsPrimary>0</IsPrimary> 
        </phone> 
        </Report_Entry> 
        <Report_Entry> 
        <IsActive>1</IsActive> 
        <PID>222</PID> 
        <phone> 
         <PhoneNumber>(101)222-1111</PhoneNumber> 
         <PhoneType>Mobile</PhoneType> 
         <IsPrimary>0</IsPrimary> 
        </phone> 
        </Report_Entry> 
        <Report_Entry> 
        <IsActive>1</IsActive> 
        <PID>333</PID> 
        <phone> 
         <PhoneNumber>(101)333-1111</PhoneNumber> 
         <PhoneType>Phone</PhoneType> 
         <IsPrimary>0</IsPrimary> 
        </phone> 
        <phone> 
         <PhoneNumber>(101)333-2222</PhoneNumber> 
         <PhoneType>Mobile</PhoneType> 
         <IsPrimary>1</IsPrimary> 
        </phone> 
        <location> 
         <location-state>NY</location-state> 
        </location> 
        <location> 
         <location-state>DC</location-state> 
        </location> 
        </Report_Entry> 
    </Report_Data> 
    ') 
    
    select 
         c.value('IsActive[1]','varchar(1)') as IsActive 
        , c.value('PID[1]','varchar(5)') as PID 
        , case when c.value('phone[1]/IsPrimary[1]','int') = 1 then c.value('phone[1]/PhoneNumber[1]','varchar(15)') end as PublicWorkPhone /** this condition needs to look at all sub nodes. this stops at the first one. **/ 
        , c.value('location[1]','varchar(2)') as location 
    from 
        #temp 
        cross apply #temp.XMLData.nodes('/Report_Data/Report_Entry') as y(c) 
    
    drop table #temp 
    GO 
    

    : SQL 서버 2012-

  • 은 (분리) 한 결합 필드

의 Runnable 코드 블록을 생성하는 모든 하위 노드를 결합 필요합니다 :

IsActive PID PublicWorkPhone location 
-------- ----- --------------- -------- 
1  111 (101)111-1111 NULL 
1  222 NULL   NULL 
1  333 (101)333-2222 NY,DC 

PID가 333 인 경우 기본 전화는 (101)333-2222이며 null이 아닙니다. 또한 해당 위치는 NY가 아닌 "NY, DC"여야합니다.

결과를 얻을 수있는 도움을 주시면 감사하겠습니다. 는

+0

이것은 좋은 질문입니다. 복사 가능한 테스트 시나리오, 자체 노력, 잘못된 출력, 예상 출력. 내 측면에서 +1 – Shnugo

+0

@ Shnugo, 고마워! – sch

답변

0

이 트릭을 할해야합니다 감사합니다

WITH prep AS 
(
    SELECT 
    c.value('(IsActive[1]/text())[1]','char(1)') as IsActive, 
    c.value('(PID[1]/text())[1]','varchar(5)') as PID, 
    c.value('(phone[IsPrimary=1]/PhoneNumber/text())[1]', 'varchar(15)') AS PublicWorkPhone, 
    location = cc.value('(text())[1]', 'varchar(1000)') 
    from #temp 
    CROSS APPLY #temp.XMLData.nodes('/Report_Data/Report_Entry') as y(c) 
    OUTER APPLY c.nodes('location/location-state') AS z(cc) 
) 
SELECT 
    IsActive, 
    PID, 
    PublicWorkPhone, 
    Location = 
    STUFF ((
    SELECT ',' + location 
    FROM prep pp 
    WHERE p.PID = pp.PID 
    FOR XML PATH('')),1,1,'') 
FROM prep p 
GROUP BY IsActive, PID, PublicWorkPhone; 
+0

솔루션에 감사드립니다. 이것은 나를 위해 속임수를했다. – sch

1

나의 제안은 입니다 전화 노드, 당신의 위치에 대한 XQuery α- 함수 data()을 찾을 수 .nodes()에서 XQuery를 사용합니다. 이 함수는 포함 된 모든 텍스트 부분을 공백으로 구분하여 반환합니다 (Btw : 구분 문자로 전달할 수없는 이상한 점 ...). 귀하의 경우에는 고체 2 문자 위치 코드가 필요합니다. 공백을 쉼표로 바꾸면됩니다.

SELECT re.value(N'IsActive[1]','bit') AS IsActive 
     ,re.value(N'PID[1]','int') AS PID 
     ,ph.value(N'PhoneNumber[1]','nvarchar(max)') AS PublicWorkPhone 
     ,REPLACE(re.query(N'data(location/location-state)').value('.','nvarchar(max)'),' ',',') AS location 
FROM #temp AS tmp 
CROSS APPLY tmp.XMLData.nodes(N'/Report_Data/Report_Entry') AS A(re) 
OUTER APPLY re.nodes(N'phone[IsPrimary=1]') AS B(ph); 
+0

내 요청을 도와 주셔서 감사합니다. 나는 NY, DC를 얻기 위해 당신의 교체 논리를 사용할 것입니다. 그런 식으로 하나의 테이블로 작업하고 있습니다. – sch

+0

@sch 나는 당신이 * 하나의 테이블을 가지고 일하는 그런 식으로는 실제로는 의미가 있지만, 나는 당신이 해결책을 찾았다는 것을 알고있다. 제게 한 가지 힌트를 주 시옵소서. * 고맙습니다 *라고 말하는 것은 투표와 수락입니다. 당신은 다른 대답을 받아 들였습니다. 이것은 완벽하게 정상적으로 당신에게 달려 있습니다. 15 포인트의 국경을 넘었으므로 추가 투표가 허용됩니다. 투표는 배지와 특권을 고려하여 계산됩니다. – Shnugo

+0

귀하의 답변에 투표했습니다. 나는 그것이 문제를 해결할 때 다른 해결책을 받아 들였다. 전화를 사용할 수 없을 때 NULL 값을 반환했습니다 IsActive PID PublicWorkPhone Location ' '-------- ----- --------------- --- ------ ''1 111 (101)111-1111 NULL' 1 '222'NULL NULL' 1 333 (101)333-2222 NY, DC' VS 이 isActive 'PID PublicWorkPhone 위치 ' '-------- ----- --------------- ---------' '1 111 (101) 111- 1111' '1 222 NULL' '1 333 (101)333-2222 NY, DC' – sch