Search code examples
c#asp.netsql-serverxmlopenxml

Working with OpenXML


I am passing XML to SQL Server stored procedure and trying it to store in #temp table.

The stored procedure is given below:

EXEC sp_xml_preparedocument @i OUTPUT  
,@XMLDOC  

 SELECT Id  
 ,UserId  
 ,ModifiedOn  
 ,ModifiedBy  
 ,ModifiedIp  
 ,DetailId
INTO #temp  
FROM OPENXML(@i, '/Root/Rec/Detail', 1) WITH (  
id INT '../@Id'  
,UserId INT '../@UserId'  
,ModifiedOn DATETIME '../@ModifiedOn'  
,ModifiedBy INT '../@ModifiedBy'  
,ModifiedIp VARCHAR(15) '../@ModifiedIp'  
,DetailId INT '@DetailId' 

)  

EXEC sp_xml_removedocument @i  

select * from #temp

And the sample of XML:

<root>
    <rec id="I001" userid="316" modifiedon="9/10/2016 02:33:56 PM" modifiedby="316" modifiedip="::1" UserDetail="System.Collections.Generic.List`1[Dto.UserDetail]">
    </rec>
</root>

When the XML contains child nodes (detail), this SP will work fine. If I don't have child nodes - it will not work. Could you point out where I went wrong?


Solution

  • Totally rewrite answer:

    DECLARE @i int,
            @XMLDOC VARCHAR(max)= "INPUT XML"
    
    EXEC sp_xml_preparedocument @i OUTPUT  
    ,@XMLDOC  
    
    SELECT *
    INTO #temp
    FROM (
    SELECT  m.Id,
            m.UserId,
            m.ModifiedOn,
            m.ModifiedBy,  
            m.ModifiedIp,  
            COALESCE(det.DetailId, -1) as DetailId
    FROM OPENXML(@i, '/root/rec', 1) WITH (  
            id INT '@availabilityid',  
            UserId INT '@userid',  
            ModifiedOn DATETIME '@modifiedon',
            ModifiedBy INT '@modifiedby',  
            ModifiedIp VARCHAR(15) '@modifiedip'
    ) as m
    LEFT JOIN (
        SELECT  Id,
                DetailId
        FROM OPENXML(@i, '/root/rec/userturnarounddetail', 1) WITH (  
                id INT '../@availabilityid',
                DetailId INT '@availabilitydetailid' 
                )
        ) as det
        ON m.id =det.id
    ) p
    
    
    EXEC sp_xml_removedocument @i  
    
    select * from #temp
    

    Output:

    Id      UserId  ModifiedOn              ModifiedBy  ModifiedIp  DetailId
    113367  316     2016-09-11 11:01:09.000 316         ::1         300100
    0       316     2016-09-11 11:01:11.000 316         ::1         -1
    

    EDIT

    Example with .nodes method. It is available since SQL Server 2008.

    DECLARE @XMLDOC xml 
    
    SELECT @XMLDOC = 
    '<root>
        <rec id="I001" userid="316" modifiedon="9/10/2016 02:33:56 PM" modifiedby="316" modifiedip="::1" UserDetail="System.Collections.Generic.List1[Dto.UserDetail]">
        </rec>
    </root>'
    
    SELECT  ISNULL(d.f.value('@id','nvarchar(15)'),d.f.value('../@id','nvarchar(15)')) as id,
            ISNULL(d.f.value('@userid','int'),d.f.value('../@userid','int')) as UserId,
            ISNULL(d.f.value('@modifiedon','datetime'),d.f.value('../@modifiedon','datetime')) as ModifiedOn,
            ISNULL(d.f.value('@modifiedby','int'),d.f.value('../@modifiedby','int')) as ModifiedBy,
            ISNULL(d.f.value('@modifiedip','nvarchar(15)'),d.f.value('../@modifiedip','nvarchar(15)')) as ModifiedIp,
            d.f.value('@detailid','int') as DetailId
    FROM @XMLDOC.nodes('//*//*') as d(f)