2016-09-29 2 views
2

В приведенном ниже примере кода T-SQL я пытаюсь запросить связанные фрагменты данных, которые находятся в разных узлах в xml, но я не могу понять, как это сделать. Например, значения LX01_AssignedNumber и C00302_ProcedureCode необходимо сместить вместе для одной и той же записи. Результат должен выглядеть следующим образом.sql server query xml связанные узлы

CLAIM_SOURCE_ID ITEM_NUMBER HCPCS_LINE_CODE 

16202E123456 1   99203 

16202E123456 2   96372 

Может кто-нибудь мне помочь?

USE [tempdb]; 
    GO 

    DECLARE @XML XML = 
    N'<ns1:X12EnrichedMessage xmlns:ns1="http://schemas.microsoft.com/BizTalk/EDI/EDIFACT/2006/EnrichedMessageXML"> 
     <TransactionSet> 
     <!-- ProcessLogID=PLG0007182226 ;ProcessLogDetailID=PLG0007182968 ;EnvID=1;RetryCount=1 --> 
     <ns0:X12_00501_837_P xmlns:ns0="http://schemas.microsoft.com/BizTalk/EDI/X12/2006"> 
      <ns0:TS837_2000A_Loop xmlns:ns0="http://schemas.microsoft.com/BizTalk/EDI/X12/2006"> 
      <ns0:TS837_2000B_Loop xmlns:ns0="http://schemas.microsoft.com/BizTalk/EDI/X12/2006"> 
       <ns0:TS837_2300_Loop xmlns:ns0="http://schemas.microsoft.com/BizTalk/EDI/X12/2006"> 
       <ns0:TS837_2400_Loop> 
        <ns0:LX_ServiceLineNumber> 
        <LX01_AssignedNumber>1</LX01_AssignedNumber> 
        </ns0:LX_ServiceLineNumber> 
        <ns0:SV1_ProfessionalService> 
        <ns0:C003_CompositeMedicalProcedureIdentifier> 
         <C00301_ProductorServiceIDQualifier>HC</C00301_ProductorServiceIDQualifier> 
         <C00302_ProcedureCode>99203</C00302_ProcedureCode> 
         <C00303_ProcedureModifier>25</C00303_ProcedureModifier> 
         <C00307_Description>NO DESCRIPTION</C00307_Description> 
        </ns0:C003_CompositeMedicalProcedureIdentifier> 
        <SV102_LineItemChargeAmount>167.82</SV102_LineItemChargeAmount> 
        <SV103_UnitorBasisforMeasurementCode>UN</SV103_UnitorBasisforMeasurementCode> 
        <SV104_ServiceUnitCount>1</SV104_ServiceUnitCount> 
        <ns0:C004_CompositeDiagnosisCodePointer> 
         <C00401_DiagnosisCodePointer>1</C00401_DiagnosisCodePointer> 
        </ns0:C004_CompositeDiagnosisCodePointer> 
        </ns0:SV1_ProfessionalService> 
        <ns0:DTP_SubLoop_2> 
        <ns0:DTP_Date_ServiceDate> 
         <DTP01_DateTimeQualifier>472</DTP01_DateTimeQualifier> 
         <DTP02_DateTimePeriodFormatQualifier>RD8</DTP02_DateTimePeriodFormatQualifier> 
         <DTP03_ServiceDate>20160627-20160627</DTP03_ServiceDate> 
        </ns0:DTP_Date_ServiceDate> 
        </ns0:DTP_SubLoop_2> 
       </ns0:TS837_2400_Loop> 
       <ns0:TS837_2400_Loop> 
        <ns0:LX_ServiceLineNumber> 
        <LX01_AssignedNumber>2</LX01_AssignedNumber> 
        </ns0:LX_ServiceLineNumber> 
        <ns0:SV1_ProfessionalService> 
        <ns0:C003_CompositeMedicalProcedureIdentifier> 
         <C00301_ProductorServiceIDQualifier>HC</C00301_ProductorServiceIDQualifier> 
         <C00302_ProcedureCode>96372</C00302_ProcedureCode> 
         <C00307_Description>NO DESCRIPTION</C00307_Description> 
        </ns0:C003_CompositeMedicalProcedureIdentifier> 
        <SV102_LineItemChargeAmount>82.56</SV102_LineItemChargeAmount> 
        <SV103_UnitorBasisforMeasurementCode>UN</SV103_UnitorBasisforMeasurementCode> 
        <SV104_ServiceUnitCount>2</SV104_ServiceUnitCount> 
        <ns0:C004_CompositeDiagnosisCodePointer> 
         <C00401_DiagnosisCodePointer>2</C00401_DiagnosisCodePointer> 
        </ns0:C004_CompositeDiagnosisCodePointer> 
        </ns0:SV1_ProfessionalService> 
        <ns0:DTP_SubLoop_2> 
        <ns0:DTP_Date_ServiceDate> 
         <DTP01_DateTimeQualifier>472</DTP01_DateTimeQualifier> 
         <DTP02_DateTimePeriodFormatQualifier>RD8</DTP02_DateTimePeriodFormatQualifier> 
         <DTP03_ServiceDate>20160627-20160627</DTP03_ServiceDate> 
        </ns0:DTP_Date_ServiceDate> 
        </ns0:DTP_SubLoop_2> 
       </ns0:TS837_2400_Loop> 
       </ns0:TS837_2300_Loop> 
      </ns0:TS837_2000B_Loop> 
      </ns0:TS837_2000A_Loop> 
     </ns0:X12_00501_837_P> 
     </TransactionSet> 
    </ns1:X12EnrichedMessage>' 

    IF OBJECT_ID(N'tempdb..#CLAIM_XML', N'U') IS NOT NULL 
     DROP TABLE #CLAIM_XML; 

    CREATE TABLE #CLAIM_XML (
     CLAIM_SOURCE_ID VARCHAR(20) NOT NULL 
    ,RAW_XML XML NOT NULL 
    ,CLAIM_FORM_TYPE CHAR(1) NOT NULL 
    ,CREATED_DATE DATE NOT NULL 
    ,CONSTRAINT CLAIM_XML_PK PRIMARY KEY (CLAIM_SOURCE_ID) 
    ); 

    CREATE PRIMARY XML INDEX CLAIM_XML_RAW_XML_IDX 
     ON #CLAIM_XML (RAW_XML); 

    INSERT INTO #CLAIM_XML 
      ([CLAIM_SOURCE_ID] 
      ,[RAW_XML] 
      ,[CLAIM_FORM_TYPE] 
      ,[CREATED_DATE]) 
    VALUES('16202E123456' 
      ,@XML 
      ,'H' 
      ,CONVERT(DATE, DATEADD(DAY, -1, GETDATE()))); 

    WITH XMLNAMESPACES ('http://schemas.microsoft.com/BizTalk/EDI/EDIFACT/2006/EnrichedMessageXML' AS ns1 
         ,'http://schemas.microsoft.com/BizTalk/EDI/X12/2006' AS ns0) 
    SELECT [CX].[CLAIM_SOURCE_ID] 
      ,[ITEM_NUMBER] = LineNumber.ref.value('text()[1]', 'int') 
      ,[HCPCS_LINE_CODE] = [CX].[RAW_XML].value('(/ns1:X12EnrichedMessage/TransactionSet/ns0:X12_00501_837_P/ns0:TS837_2000A_Loop/ns0:TS837_2000B_Loop/ns0:TS837_2300_Loop/ns0:TS837_2400_Loop/ns0:SV1_ProfessionalService/ns0:C003_CompositeMedicalProcedureIdentifier/C00302_ProcedureCode)[1]','varchar(100)') 
     FROM #CLAIM_XML AS [CX] 
    CROSS APPLY [CX].[RAW_XML].nodes('/ns1:X12EnrichedMessage/TransactionSet/ns0:X12_00501_837_P/ns0:TS837_2000A_Loop/ns0:TS837_2000B_Loop/ns0:TS837_2300_Loop/ns0:TS837_2400_Loop/ns0:LX_ServiceLineNumber/*') LineNumber(ref) 
    WHERE [CX].[CLAIM_FORM_TYPE] = 'H' 
     AND [CX].[CREATED_DATE] = CONVERT(DATE, DATEADD(DAY, -1, GETDATE())); 

ответ

1

использовать несколько CROSS APPLY s, чтобы получить доступ к различным частям из XML, например:

;WITH XMLNAMESPACES ('http://schemas.microsoft.com/BizTalk/EDI/EDIFACT/2006/EnrichedMessageXML' AS ns1 
        ,'http://schemas.microsoft.com/BizTalk/EDI/X12/2006' AS ns0) 
SELECT 
    c.[CLAIM_SOURCE_ID], 
    sln.c.value('(LX01_AssignedNumber/text())[1]', 'INT') AS [ITEM_NUMBER], 
    ps.c.value('(ns0:C003_CompositeMedicalProcedureIdentifier/C00302_ProcedureCode/text())[1]', 'INT') AS [HCPCS_LINE_CODE] 
FROM #CLAIM_XML c 
    CROSS APPLY c.[RAW_XML].nodes('/ns1:X12EnrichedMessage/TransactionSet/ns0:X12_00501_837_P/ns0:TS837_2000A_Loop/ns0:TS837_2000B_Loop/ns0:TS837_2300_Loop/ns0:TS837_2400_Loop') l(c) 
     CROSS APPLY l.c.nodes('ns0:LX_ServiceLineNumber') sln(c) 
     CROSS APPLY l.c.nodes('ns0:SV1_ProfessionalService') ps(c) 
+0

Привет wBob, тем глубже 'CROSS APPLY' не нужны ... вы их должны были бы, если бы ожидать несколько мест где' ns0: LX_ServiceLineNumber' или 'ns0: SV1_ProfessionalService'. Лучше обращаться к этим значениям напрямую. – Shnugo

0

Нет необходимости в нескольких CROSS APPLY с .nodes(). По мере того как значения, которые вы хотите прочитать являются одного вхождение в их дереве вы можете обратиться к ним напрямую:

;WITH XMLNAMESPACES ('http://schemas.microsoft.com/BizTalk/EDI/EDIFACT/2006/EnrichedMessageXML' AS ns1 
        ,'http://schemas.microsoft.com/BizTalk/EDI/X12/2006' AS ns0) 
SELECT 
    loop2400.value('(ns0:LX_ServiceLineNumber/LX01_AssignedNumber)[1]', 'INT') AS [ITEM_NUMBER], 
    loop2400.value('(ns0:SV1_ProfessionalService/ns0:C003_CompositeMedicalProcedureIdentifier/C00302_ProcedureCode)[1]', 'INT') AS [HCPCS_LINE_CODE] 
FROM @xml.nodes('/ns1:X12EnrichedMessage/TransactionSet/ns0:X12_00501_837_P/ns0:TS837_2000A_Loop/ns0:TS837_2000B_Loop/ns0:TS837_2300_Loop/ns0:TS837_2400_Loop') A(loop2400) 

ленивый подход тоже работает, но - в общем - это хорошо советуют быть как можно .. .

SELECT 
    loop2400.value('(*//LX01_AssignedNumber)[1]', 'INT') AS [ITEM_NUMBER], 
    loop2400.value('(*//C00302_ProcedureCode)[1]', 'INT') AS [HCPCS_LINE_CODE] 
FROM @xml.nodes('//*:TS837_2400_Loop') A(loop2400)