2011-12-11 13 views
5

mam pewne problemy przy użyciu exist() i value() metod w SQL Server 2008.SQL Server XML istnieje()

Moje XML wygląda następująco:

<?xml version="1.0" encoding="UTF-8"?> 
<library> 
    <branches> 
     <branch> 
      <codelib>1</codelib> 
      <name>Campus</name> 
     </branch> 
     <branch> 
      <codelib>2</codelib> 
      <name>47th</name> 
     </branch> 
     <branch> 
      <codelib>3</codelib> 
      <name>Mall</name> 
     </branch>    
    </branches> 
    <books> 
     <book type="SF"> 
      <codb>11</codb> 
      <title>Robots</title> 
      <authors> 
       <author>author1 robots</author> 
       <author>author2 robots</author> 
      </authors> 
      <price>10</price> 
      <stocks> 
       <branch codelib="1" amount="10"/> 
       <branch codelib="2" amount="5"/> 
       <branch codelib="4" amount="15"/> 
      </stocks> 
      <from>20</from> 
      <to>30</to> 
     </book> 
     <book type="poetry"> 
      <codb>12</codb> 
      <title>Poetry book</title> 
      <authors> 
       <author>AuthorPoetry</author> 
      </authors> 
      <price>14</price> 
      <stocks> 
       <branch codelib="1" amount="7"/> 
       <branch codelib="2" amount="5"/> 
      </stocks> 
      <from>25</from> 
      <to>40</to> 
     </book>  
     <book type="children"> 
      <codb>19</codb> 
      <title>Faitytales</title> 
      <authors>    
       <author>AuthorChildren</author>    
      </authors> 
      <price>20</price> 
      <stocks> 
       <branch codelib="1" amount="10"/> 
       <branch codelib="3" amount="55"/> 
       <branch codelib="4" amount="15"/> 
      </stocks> 
      <from>70</from> 
      <to>75</to> 
     </book>  
     <book type="literature"> 
      <codb>19</codb> 
      <title>T</title> 
      <authors> 
       <author>A</author>     
      </authors> 
      <price>17</price> 
      <stocks> 
       <branch codelib="1" amount="40"/> 
      </stocks> 
      <from>85</from> 
      <to>110</to> 
     </book> 
    </books> 
</library> 

Biorąc pod uwagę to XML, muszę napisać SELECT Klauzula, która będzie używać następujących po sobie 2 razy, co najmniej jeden raz: query(), value() i exist(). Nie mogę nawet użyć query() i exist() w tym samym SELECT, ponieważ wydaje się, że klauzula WHERE nie ma żadnego wpływu.

Na przykład, chcę, aby pobrać wszystkie <branch> elementy, które są dzieci książki z typem SF, ale select

declare @genre varchar(15) 
    set @genre = 'SF' 
    SELECT XMLData.query('//branch') from TableA 
    WHERE XMLData.exist('//book[./@type = sql:variable("@genre")]') = 1 

pobiera wszystkie elementy <branch>, a nie tylko te z ukierunkowane książka. Nie mogę rozgryźć, co jest nie tak z moim wyborem. Również byłbym wdzięczny mały przykład z query(), exist() i value() w tym samym wybrać (jest to możliwe, aby mieć zagnieżdżone wybierz oświadczeń w SQL XML?)

Odpowiedz

7

dobrze, wyrażenie XPath tutaj jest „winowajcą”:

query('//branch') 

To mówi: wybierz wszystkie węzły z całego dokumentu: wszystkie . Po prostu robisz to, co chcesz, naprawdę ...

Co jest nie tak z tym zapytaniem?

SELECT 
    XMLData.query('/library/books/book[@type=sql:variable("@genre")]//branch') 
FROM dbo.TableA 

To by pobrać wszystkie <branch> podwęzły węzła <book> który ma type="SF" jako atrybut ....

Co chcesz osiągnąć dzięki query(), exist() i value() wszystkich w tej samej instrukcji ?? Całkiem możliwe, że można to zrobić o wiele łatwiej ...

Także: Myślę, że źle interpretujesz to, co robi .exist() w SQL Server XQuery. Jeśli masz swoje oświadczenie tutaj:

SELECT (some columns) 
FROM dbo.TableA 
WHERE XMLData.exist('//book[@type = sql:variable("@genre")]') = 1 

jesteś w zasadzie informacją SQL Server, aby pobrać wszystkie wiersze z dbo.TableA gdzie XML przechowywane w XMLData zawiera <book type=.....> węzeł - zaznaczania wierszy z tabeli - NIE stosujące wybór do zawartości kolumny XMLData ...

+0

Nie jest to, że chcę, ale muszę użyć zarówno query(), value() i exist() w tej samej instrukcji. Dlatego chcę dokonać filtrowania jak w T-SQL, SELECT ... WHERE ... może coś jak zagnieżdżone instrukcje SELECT, jeśli to możliwe. Chcę tylko przykład, jak osiągnąć coś takiego. – joanna

3

Podany kod XML nie nadaje się do instrukcji exist. Gdybyś miał wiele instrukcji XML i musiał znaleźć ten, w którym zawierał jakąś wartość, wtedy instrukcja byłaby bardziej trafna.

Podana przez ciebie klauzula sprawdza, czy warunek istnieje, a jeśli tak, zaznacza wszystkie elementy branches, a nie tylko te, w których warunek jest spełniony. Na przykład, następujący (oczywiście) nie zwraca niczego:

SELECT @xmldata.query('//branch') from TableA 
WHERE @xmldata.exist('//book[./@type = "BLAH"]') = 1 

Ale tu jest coś pokazać można wykorzystać wszystkie trzy w jednym SELECT.

SELECT T.c.query('./title').value('.', 'varchar(250)') as title, 
     T.c.exist('.[@type eq "SF"]') as IsSF 
    from @xmldata.nodes('//book') T(c) 
+0

Podany przez ciebie SELECT jest bliski temu, czego potrzebuję, tnx. Ostatni problem ... czy można mieć coś takiego jak SELECT ... WHERE x = (SELECT..WHERE), dzięki czemu mogę używać wartości(), exist() i query() 2 razy? Zasadniczo, wybierz (ze wszystkimi 3 funkcjami), które będą filtrować niektóre wartości, a następnie inny, który używa filtrowanych węzłów? – joanna

0

Przepraszam, jeśli to się spóźnia, ale widziałem tylko ten post.

Jest wydajniejszy, ponieważ XML filtruje za pomocą operatora stosowania krzyżowego w celu filtrowania do wymaganego węzła, a następnie wybiera zapytanie z zwróconych węzłów. Aby przesłać zapytanie do węzłów podrzędnych, należy również uwzględnić katalog główny. w zapytaniu, więc w tym przypadku .//branch zamiast // branch.

declare @genre varchar(15) = 'SF' 
select l.query('.//branch') from TableA 
cross apply XmlData.nodes('library/books/book[@type=sql:variable("@genre")]') n (l) 

Można jeszcze dodać istnieje klauzula, jeśli chcesz, ale to faktycznie dodać dodatkowe niepotrzebne koszty

WHERE XMLData.exist('//book[./@type = sql:variable("@genre")]') = 1 

nadzieję, że to pomaga. D

Powiązane problemy