3

I have xml in following format

 <Entity>
    <name>John</name>
    <aliases><alias>Johnny</alias></aliases>
    <aliases><alias>Johnson</alias></aliases>
    </Entity>
    <Entity>
    <name>Smith</name>
    <aliases><alias>Smithy</alias></aliases>
    <aliases><alias>Schmit</alias></aliases>
    </Entity>

I want to insert them in table so the table should have 4 records in the example.

columns are name and alias.

name | alias
John | Johnny
John | Johnson
Smith| Smithy
Smith| Schmit

How can I achive this using cursor or something else?

What i have tried. In cursor for entity i try insert alias value,but only first alias is taken.

insert into  TESTTABLE
            (EntityID,Alias)
        select 
            @EntityID as EntityID,
            Alias
        from OpenXml(@ixml, '/Aliases',2)
        with (
            Alias varchar(255) '.'
        )   
2
  • Refer: stackoverflow.com/a/21378920/4358787 Commented May 28, 2018 at 8:28
  • @gaurav thank you for the reference but because the structure is <aliases><alias> for each alias it is not working for me Commented May 28, 2018 at 8:48

2 Answers 2

2
DECLARE @XML AS XML= N'
<Entity>
    <name>John</name>
    <aliases><alias>Johnny</alias></aliases>
    <aliases><alias>Johnson</alias></aliases>
    </Entity>
    <Entity>
    <name>Smith</name>
    <aliases><alias>Smithy</alias></aliases>


     <aliases><alias>Schmit</alias></aliases>
        </Entity>'

INSERT INTO @tblTest(firstName,LastName)
        SELECT  t1.c.value('../name[1]','varchar(100)') As FirstName,t1.c.value('alias[1]','varchar(50)') as SecondName

    FROM @xml.nodes('/Entity/aliases') t1(c)
Sign up to request clarification or add additional context in comments.

5 Comments

I will try, I have to mention that there can be any number of alias 0 to n
<aliases><alias>Smithy</alias><alias>Schmit</alias></aliases> if i have aliases with multiple alias it gets only the first one, how can also include this in the solution, otherwise this answer is correct for the example.
alias[1] can be replaced with .
In general it is not a good idea to hop back (../name[1])... And it's faster to use (somenode/text())[1] instead of somenode[1]. You migtht want to read this related answer
@MasterYi Your trick to replace alias[1] with a simple . works in this very simple case, but is a dangerous and not recommended approach. The general advise is: Be as specific as possible
1

First of all: Your XML is not well-formed as it is missing a root node. SQL-server can deal with XML-fragments, but other engines might fail...

You have a 1:n related two level hierarchy. This is best queried with a cascade of .nodes():

DECLARE @XML AS XML= 
N'<Entity>
    <name>John</name>
    <aliases>
    <alias>Johnny</alias>
    </aliases>
    <aliases>
    <alias>Johnson</alias>
    </aliases>
</Entity>
<Entity>
    <name>Smith</name>
    <aliases>
    <alias>Smithy</alias>
    </aliases>
    <aliases>
    <alias>Schmit</alias>
    </aliases>
</Entity>' 

--the query will use .nodes() to get all entities and a second time .nodes() to get a derived table of the aliases below each entity.

SELECT  A.ent.value('(name/text())[1]','varchar(100)') As FirstName
       ,B.ali.value('(alias/text())[1]','varchar(50)') as SecondName
FROM @xml.nodes('/Entity') A(ent)
CROSS APPLY A.ent.nodes(N'aliases') AS B(ali);

UPDATE added attributes

According to one comment below I changed this a bit to reflect multiple aliases with an attribute.

DECLARE @XML AS XML= 
N'<Entity>
    <name>John</name>
    <aliases>
    <alias nr="1">Johnny</alias>
    <alias nr="2">OneMore</alias>
    </aliases>
    <aliases>
    <alias>Johnson</alias>
    </aliases>
</Entity>
<Entity>
    <name>Smith</name>
    <aliases>
    <alias nr="1">Smithy</alias>
    </aliases>
    <aliases>
    <alias nr="1">Schmit</alias>
    </aliases>
</Entity>' 

SELECT  A.ent.value('(name/text())[1]','varchar(100)') As FirstName
       ,B.ali.value('@nr','int') as SomeAttribute
       ,B.ali.value('text()[1]','varchar(50)') as SecondName
FROM @xml.nodes('/Entity') A(ent)
CROSS APPLY A.ent.nodes(N'aliases/alias') AS B(ali);

What has changed?

  • .nodes() is diving one level deeper to /alias, thus repeating multiple aliases in multiple rows.
  • reading the attribute with a leading @

1 Comment

Thank you! Great and simple solution. One Question what if alias would have an Attribute (like : <alias nr="1">Schmit</alias>) can i read it too the same way?

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.