Търсене на елемент *без* даден дъщерен елемент (където дъщерният елемент е променлива)

В SQL Server 2008 искам да идентифицирам елементи, които не съдържат даден дъщерен елемент в случай, че името на дъщерния елемент е динамично. В този XML и трите li елемента съдържат F1 и F2 дъщерни елементи, а 2-ри и 3-ти li правят не съдържат елемент ръбове. Мога да намеря liбез edges деца, ако името на елемента edges е известно предварително - вижте exist< /em> заявка по-долу, която връща 1, както трябва.

declare @x xml = '<data>
  <li>
    <F1>ellipse</F1>
    <F2 />
    <edges/>
  </li>
  <li>
    <F1>triangle</F1>
    <F2>3</F2>
  </li>
  <li>
    <F1>square</F1>
    <F2>4</F2>
  </li>
</data>';

select @x.exist('/data/li[not(F1)]') -- returns 0, there is no li without an F1 (OK)
select @x.exist('/data/li[not(edges)]') -- returns 1, there is an li without edges (OK)

Но ако стойността на ръбове не е известна предварително, как да я посоча с помощта на SQL променлива? Бих искал да кодирам нещо като следното:

declare @ChildElement varchar(100) = 'edges';
select @x.exist('/data/li[not(sql:variable("@ChildElement"))]') -- not allowed

но sql:променлива не е валидна в този контекст в SQL Server. Опитах също комбинации с помощта на local-name():

select @x.exist('/data/li[not(local-name()=sql:variable("ChildElement"))]') -- always returns 1

но винаги връща 1. Мисля, че защото винаги има li с дъщерен елемент, който не е F1, и винаги има li с дъщерен елемент, който не е ръбове. Как мога да идентифицирам само li без поделемента edges, ако edges е в SQL променлива? Между другото, използвам SQL Server 2008, въпреки че мисля, че това важи за всички версии на SQL Server от 2005 г. нагоре.


person Ubercoder    schedule 15.06.2014    source източник


Отговори (1)


Предполагам, че първият ви подход не работи, тъй като променливата е „заменена“ от низ (не познавам XQuery възможностите на SQL Server достатъчно добре, за да обясня какво се случва в детайли).

Вторият подход е запитване до всички li елементи, където local-name() на li елемента (текущ контекст!) е равно на SQL променливата – вероятно не това, което искате да направите. Вместо това опитайте

select @x.exist('/data/li[not(./*[local-name()=sql:variable("@ChildElement")])]')

който вместо това тества всички деца.

person Jens Erat    schedule 15.06.2014
comment
Това ./ необходимо ли е? Знам, че XPath в SQL Server има някои странности, но че ./ няма да е необходимо в стандартния XPath. - person JLRishe; 15.06.2014
comment
@JLRishe не, ./ не е необходимо в SQL Server. * е достатъчно. +1 - person Mikael Eriksson; 15.06.2014
comment
Някои потребители на XPath използват ./ като начин да привлекат вниманието на читателя към факта, че пътят е относителен, а не абсолютен. Не знам дали това беше намерението на Йенс Ерат, но затова често използвам ./ за започване на относителни пътища. - person C. M. Sperberg-McQueen; 15.06.2014
comment
@JLRishe: това, което C. M. Sperberg-McQueen казва, е точно това, което правя. Ако използването на текущия контекст е под съмнение, обикновено изрично го обозначавам. Най-често в началото на заявка, за да подскажа, че не съм забравил корена /. - person Jens Erat; 16.06.2014
comment
Jens / Mikael - току-що го пробвах (с ./*) и работи перфектно. Предполагам, че * означава, че трябва да провери всички поделементи в li, за да се увери, че не съвпадат, което е точно това, от което имах нужда. Благодаря за помощта - ще маркирам това като приет отговор. - person Ubercoder; 16.06.2014
comment
Този израз означава повече или по-малко всички li, които нямат деца, чието име е равно на SQL променливата, така че да, точно както го описахте в коментара си. - person Jens Erat; 16.06.2014