views:

263

answers:

2

I have imported an xml document into SQL Server, I am now trying to import various parts into different tables. When I use the below query it only returns one row of hotel_facilities, I need to return all the hotel_facilities with the hotel_ref.

DECLARE @Details xml 
    SET @Details = '<hotels>
 <hotel>
  <hotel_ref>105</hotel_ref> 
 <hotel_facilities>
  <id>2</id> 
  <name>Disabled Facilities</name> 
  <id>4</id> 
  <name>24 Hour Reception</name> 
  <id>12</id> 
  <name>Restaurant</name> 
  </hotel_facilities>
  </hotel>
</hotels>'  

SELECT tab.col.value('../hotel_ref[1]','varchar(100)') AS 'hotel_ref',
tab.col.value('./id[1]','varchar(100)') AS 'HotelFacilityID',
tab.col.value('./name[1]','varchar(100)') AS 'HotelFacilityName'
FROM @Details.nodes('//hotels/hotel/hotel_facilities') AS tab(col)
+2  A: 

Your XML is structured a bit funny - the <hotel_facilities> doesn't contain a proper "sub-entity" which you could enumerate over......

If your facilities would be wrapped into a <facility>....</facility> element, you could easily enumerate that.

   <hotel_facilities>
      <facility>
         <id>2</id> 
         <name>Disabled Facilities</name> 
      </facility>
      <facility>
         <id>4</id> 
         <name>24 Hour Reception</name> 
      </facility>
      <facility>
         <id>12</id> 
         <name>Restaurant</name> 
      </facility>
   </hotel_facilities>

But with your current setup, I think you'll be hard-pressed to find a good solution....

marc_s
A: 

I agree with marc_s The XML does not have a good schema.

The closest I could get is:

SELECT tab.col.value('./hotel_ref[1]','varchar(100)') AS 'hotel_ref', 
fac.value('(.)[1]','varchar(100)') AS 'HotelFacilityID', 
ROWID=IDENTITY(int,1,1) 
into #facilitiesid 
FROM @Details.nodes('/hotels/hotel') AS tab(col) 
cross apply col.nodes('.//id') a(fac) 


SELECT tab.col.value('../hotel_ref[1]','varchar(100)') AS 'hotel_ref', 
fac.value('(.)[1]','varchar(100)') AS 'HotelFacilityName', 
ROWID=IDENTITY(int,1,1) 
into #facilitiesnames 
FROM @Details.nodes('//hotels/hotel/hotel_facilities') AS tab(col) 
cross apply col.nodes('.//name') a(fac) 

select i.hotel_ref, HotelFacilityID, HotelFacilityName 
from #facilitiesid i 
inner join #facilitiesnames n 
    on i.rowid = n.rowid 
Jose Chama
I was trying something similar, but since the "id" and "name" elements really don't have any association between them inside the <hotel_facilities> node, I am afraid at some point, you'll end up putting together an id and a name that don't belong together... but quite honestly, I don't see a better solution, either.
marc_s
You were right from the start, this is an XML schema problem. I just assumed that Steve cannot change the schema and that the order of the XML elements determine their relationship. And you are right again that we could end up with bad associations.
Jose Chama
I just recieve the xml file and have no control over it.The problem with both the solutions is when you add another hotel node with its hotel_facilities both solutions repeat the nodes for each hotel.
steve
I just added a .// to the cross apply. That should do the trick.
Jose Chama