Как мога да напиша XQuery за достъп до XML, съхранен в отделни таблици на SQL Server?

Създадох нова база данни с две таблици, за да тествам функционалността на SQLServer 2008 XML.

Ако успея да постигна желаното поведение, ще трябва да създам около 50 таблици, за да импортирам много XML файлове за нов проект.

Моята тестова среда е създадена по следния начин:

create table Employees(
    idEmployeeFeed bigint primary key IDENTITY(1,1),
    EmployeeFeed xml
)
go

create table GeoCountries(
    CountriesFeed xml
)
go

След това заредих около 1000 xml файла в таблицата Employees и 1 файл в таблицата GeoCountries. Файлът GeoCountries съдържа центроидни координати по ширина/дължина за 249 държави плюс името на държавата и кода на държавата с ISO 3 знака.

Всеки от служителите има код на държавата. Вече имах готов XQuery в друг продукт и сега имам нужда да мигрирам към SQL Server според изискванията на клиента.

Примерни данни от двете таблици, получени с XQuery:

select EmployeeFeed.query('//employee') as employee
from Employees
/* output:
    <employee empID="1111" >
      <displayName>John</displayName>
      <country code="USA" />
    </employee>
    <employee empID="2222" >
      <displayName>Mario</displayName>
      <country code="ITA" />
    </employee>
    ...
*/

select EmployeeFeed.query('//employee/country') as employee
from Employees
/* output:
    <country code="USA" />
    <country code="ITA" />
    ...
*/

select CountriesFeed.query('//country')
from GeoCountries
/* output:
    <country>
      <ISO3166A3>USA</ISO3166A3>
      <ISOen_name>United States</ISOen_name>
      <latitude>38.000</latitude>
      <longitude>-97.000</longitude>
    </country>
    <country>
      <ISO3166A3>ITA</ISO3166A3>
      <ISOen_name>Italy</ISOen_name>
      <latitude>42.833</latitude>
      <longitude>12.833</longitude>
    </country>
    ...
*/

select CountriesFeed.query('//country/ISO3166A3')
from GeoCountries
/* output:
    <ISO3166A3>USA</ISO3166A3>
    <ISO3166A3>ITA</ISO3166A3>
    ...
*/

Това е заявката, която се опитвам да изпълня:

select EmployeeFeed.query(N'
  let $ccc := //country
  let $ttt := //employee
  for $t in $ttt  
  return
        <geoEmp
        empCode="{ $t/@empID }" 
        countryCode="{ $t/country/@code }" 
        latit="{ $ccc[ISO3166A3 = $t/country/@code]/latitude/text() }" 
        longit="{ $ccc[ISO3166A3 = $t/country/@code]/longitude/text() }"
        />
') as GeoEmployees
from Employees
/* output:
    <geoEmp empCode="1111" countryCode="USA" latit="" longit="" />
    <geoEmp empCode="2222" countryCode="ITA" latit="" longit="" />
    ...
*/

Както можете да видите, кодовете на държавите + lat/long са предварително заредени в променлива $ccc, за да се използва като справочна таблица, но тъй като тези данни са в друга SQL таблица (GeoCountries), те не могат да бъдат намерени в текущия контекст на XQuery, който е свързано с SQL таблица Employees.

Има ли начин да стартирате XQuery с достъп до XML, съхраняван в отделни SQL таблици? Ще трябва да управлявам 100-200 подобни ситуации, ако мигрирам, и трябва да намеря ефективно решение за този проблем.


person MarioCannistra    schedule 21.02.2013    source източник
comment

Няма разлика. Някои класове, напр. Страницата предоставя свойство Context, което връща HttpContext.Current и може да се използва като кратка форма.

  -  person RBarryYoung    schedule 21.02.2013


Отговори (1)


Какво ще кажете за това:

select e.empID as '@empCode', c.code as '@countryCode', c.lat as '@latit', c.long as '@longit' from (
    select e.emp.value('(@empID)[1]', 'int') as empID, e.emp.value('(country/@code)[1]', 'varchar(32)') as code
    from Employees
    cross apply EmployeeFeed.nodes('//employee') e(emp)
) e
inner join (
    select c.country.value('(ISO3166A3)[1]', 'varchar(32)') as code, c.country.value('(latitude)[1]', 'varchar(32)') as lat, c.country.value('(longitude)[1]', 'varchar(32)') as long
    from GeoCountries
    cross apply CountriesFeed.nodes('//country') c(country)
) c on e.code = c.code
for xml path('geoEmp'), type
person muhmud    schedule 21.02.2013
comment
Благодаря ти мухмуд. Вашият подход работи и мога да постигна желания резултат. Просто се притеснявам за режийните разходи по отношение на сложността и количеството на кода, които изглежда са необходими за превключване от чиста xquery... По принцип тук ще преминем към междинен набор от sql данни, за да превключим обратно към xml с for xml . Има ли начин да се препрати xml в другата таблица, като се използва нещо като подход fn:doc(tablename)? Също така се чудя дали този подход може да въведе известна степен на влошаване на производителността... - person MarioCannistra; 21.02.2013
comment
Можете да създадете XML индекси, ако е необходимо. Въпреки това, ако искате да Xquery, мисля, че ще трябва да получите частите от xml на едно и също място или чрез конкатенация, или може би с sqlvariable - msdn.microsoft.com/en-us/library/ms188254.aspx. Дори и с това все още трябва да преминете през по-голямата част от вашия XML, но този път в Xquery. Можете да опитате да намалите това с клаузи where, но след това можете също да приложите това към горното. - person muhmud; 21.02.2013
comment
Имам абсолютно същия проблем и се чудех дали сте намерили начин да кажете референтни xml данни от друга таблица от XQuery (напр. fn:doc(tablename) или fn:collection(collectioname)? Или това просто не е възможно? Какво ще кажете за новите възможности на SQL Server 2014? Благодаря предварително. - person Adrian; 25.03.2014