Mark Mark -4 years ago 80
SQL Question

Inserting into relational table data from XML field

I have an XML structure that looks like the following:

SET @TheXML =
<MailingCompany>
<Mailman>
<Name>Jamie</Name>
<Age> 24 </Age>
<Letter>
<DestinationAddress> 440 Mountain View Parade </DestinationAddress>
<DestinationCountry> USA </DestinationCountry>
<OriginCountry> Australia </OriginCountry>
<OriginAddress> 120 St Kilda Road </OriginAddress>
</Letter>
</Mailman>
</MailingCompany>


Basically I have a written a query with extracts each of the children of Mailman and Letter and inserts the values into relational tables, which looks like the following:

INSERT INTO dbo.[Mailman]
SELECT
NULLIF(t.value('Name[1]','varchar(100)'),'') as Name,
NULLIF(t.value('Age[1]','varchar(10)'),'') as Age
FROM @TheXML.nodes('MailingCompany/Mailman') as MailmanTemp(t)

SET @MailPersonFK = SCOPE_IDENTITY();


INSERT INTO dbo.[Letter]
SELECT
NULLIF(t.value('DestinationAddress[1]','varchar(100)'),'') as DestinationAddress,
NULLIF(t.value('DestinationCountry[1]','varchar(100)'),'') as DestinationCountry,
NULLIF(t.value('OriginCountry[1]','varchar(100)'),'') as OriginCountry,
NULLIF(t.value('OriginAddress[1]','varchar(100)'),'') as OriginAddress
@MailPersonFK AS MailmanID
FROM @TheXML.nodes('MailingCompany/Mailman/Letter') as LetterTemp(t)


My issue is that I only want to insert into the Mailman table when node 'Name' is populated with data. Same thing for inserting into Letter with node 'DestinationAddress'.

It's may also be useful noting that the parent node is not always going to be MailingCompany, and a Mailman can have many Letters.

Thanks all!

Answer Source

I believe that altering the XPaths in your nodes() method to the following will meet your requirements:

/*/Mailman[Name[text()!=""]]

Here, we get Mailman elements as long as they are children of any top-level element, and only if they contain text data (also, implicitly, they must exist).

/*/Mailman/Letter[DestinationAddress[text()!=""]]

This one gets letters that are children of any top-level node, it will get multiple Letter elements if there are any. And applys the same test for text content.

Tested successfully on the XML you provided:

  • <Name>Jamie</Name> - returned Name and Age
  • <Name></Name> - nothing returned
  • No <Name> element - nothing returned.

And similar tests for destination address.

Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download