Search code examples
sql-serverxmlt-sqlxpathsqlxml

XMl parse in SQL Server


I have this xml structure.I use the following sql to read the values but it doesnt work

DECLARE @x XML =
'<Events>
  <Event DateTimeGMT="25/10/2013 18:45:00" Branch="Soccer" Sport="Soccer" BranchID="1" League="England - Championship" LeagueID="10099" ID="5693075" IsOption="0" EventType="0" MEID="2673883">
    <Participants>
      <Participant1 Name="Middlesbrough" Home_Visiting="Home" />
      <Participant2 Name="Doncaster" Home_Visiting="Visiting" />
    </Participants>
    <MoneyLine Home="1.69" Draw="3.7" Away="5" />
    <Spread Home_Odds="1.885" Home_Points="-0.75" Away_Points="0.75" Away_Odds="1.962" />
    <Total Points="2.75" Over="2.06" Under="1.763" />
  </Event>
  <Event DateTimeGMT="25/10/2013 18:45:00" Branch="Soccer" Sport="Soccer" BranchID="1" League="England - Championship" LeagueID="10099" ID="5693993" IsOption="1" EventType="200" MEID="2673883">
    <Participants>
      <Participant1 Name="Middlesbrough" Home_Visiting="Home" />
      <Participant2 Name="Doncaster" Home_Visiting="Visiting" />
    </Participants>
    <Total Points="4.5" Over="5.75" Under="1.125" />
  </Event>
</Events>
'
DECLARE @iDoc INT
EXECUTE sp_xml_preparedocument @iDoc OUTPUT, @x

SELECT  *
FROM    OPENXML(@iDoc,'/Events/Event')
WITH    (
ID int '@ID',
DateTimeGMT [varchar](100) '@DateTimeGMT',
Branch [varchar](100) '@Branch',
Sport [varchar](100) '@Sport',
BranchID int '@BranchID',
League [varchar](100) '@League',
LeagueID int '@LeagueID',
IsOption int '@IsOption',
EventType int '@EventType',
MEID int '@MEID',
QAID int '@QAID',
EventName [varchar](500) '@EventName',
Home [varchar](100) '../Event/Participants/Participant1/@Name',
Away [varchar](100) '../Event/Participants/Participant2/@Name',
[1] [varchar](5) '../Event/MoneyLine/@Home',
[X] [varchar](5) '../Event/MoneyLine/@Draw',
[2] [varchar](5) '../Event/MoneyLine/@Away',
Spread_Home_Points float '../Event/Spread/@Home_Points',
Spread_Home_Odds float '../Event/Spread/@Home_Odds',
Spread_Away_Points float '../Event/Spread/@Away_Points',
Spread_Away_Odds float '../Event/Spread/@Away_Odds',
Total_Points float '../Event/Total/@Points',
Lart float '../Event/Total/@Over',
Posht float '../Event/Total/@Under'
        )

EXECUTE sp_xml_removedocument @iDoc

But this doent give a correct answer. On the second row that doesnt fine MoneyLine it repeats the first row values. enter image description here

The values marked with circle showld be empty.Any help please?


Solution

  • I suggest to use nodes() method for reading xml in SQL server, it's much easier to use. For your XML it could be something like this:

    select
        T.C.value('@DateTimeGMT', 'varchar(100)') as DateTimeGMT,
        T.C.value('@Branch', 'varchar(100)') as Branch,
        T.C.value('@BranchID', 'int') as BranchID,
        T.C.value('@League', 'varchar(100)') as League,
        T.C.value('@LeagueID', 'int') as LeagueID,
        T.C.value('@IsOption', 'int') as IsOption,
        T.C.value('@EventType', 'int') as EventType,
        T.C.value('@MEID', 'int') as MEID,
        T.C.value('@QAID', 'int') as QAID,
        T.C.value('@EventName', 'varchar(500)') as EventName,
        T.C.value('(Participants/Participant1)[1]/@Name', 'varchar(100)') as Home,
        T.C.value('(Participants/Participant2)[1]/@Name', 'varchar(100)') as Away,
        T.C.value('(MoneyLine)[1]/@Home', 'varchar(5)') as [1],
        T.C.value('(MoneyLine)[1]/@Draw', 'varchar(5)') as [X],
        T.C.value('(MoneyLine)[1]/@Away', 'varchar(5)') as [2],
        T.C.value('(Spread)[1]/@Home_Points', 'float') as Spread_Home_Points,
        T.C.value('(Spread)[1]/@Home_Odds', 'float') as Spread_Home_Odds,
        T.C.value('(Spread)[1]/@Away_Points', 'float') as Spread_Away_Points,
        T.C.value('(Spread)[1]/@Away_Odds', 'float') as Spread_Away_Odds,
        T.C.value('(Spread)[1]/@Away_Odds', 'float') as Spread_Away_Odds,
        T.C.value('(Total)[1]/@Points', 'float') as Total_Points,
        T.C.value('(Total)[1]/@Over', 'float') as Lart,
        T.C.value('(Total)[1]/@Under', 'float') as Posht
    from @x.nodes('Events/Event') as T(C)
    

    sql fiddle demo

    To get data from element filtered by attribute, you can use xpath:

    select
        T.C.value('(Participants/Participant[@Name="Odd"]/Odds)[1]/@OddsValue', 'float') as Odd,
        T.C.value('(Participants/Participant[@Name="Even"]/Odds)[1]/@OddsValue', 'float') as Even
    from @x.nodes('Events/Event') as T(C)
    

    sql fiddle demo