SQL Server XML существует () - PullRequest
       1

SQL Server XML существует ()

5 голосов
/ 12 декабря 2011

У меня есть некоторые проблемы с использованием методов exist() и value() в SQL Server 2008.

Мой XML выглядит так:

<?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>

Учитывая этот XML, я должен написать предложение SELECT, которое будет использовать query(), value() и exist() 2 раза каждый, как минимум. Я даже не могу использовать query() и exist() в одном и том же SELECT, так как кажется, что предложение WHERE не имеет никакого эффекта.

Например, я хочу получить все элементы <branch>, которые являются дочерними элементами книги с типом SF, но с оператором select

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

извлекает все элементы <branch>, а не только элементы из целевой книги. Я не могу понять, что не так с моим выбором. Кроме того, я был бы признателен за небольшой пример с query(), exist() и value() в одном и том же select (возможно ли иметь вложенные операторы select в sql xml?)

Ответы [ 3 ]

7 голосов
/ 12 декабря 2011

Итак, ваше выражение XPath здесь является «виновником»:

query('//branch')

Это говорит: выберите все <branch> узлов из всего документа.Он просто делает то, о чем вы говорите, на самом деле ....

Что не так с этим запросом здесь ??

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

Это приведет к извлечению всех подузлов <branch>для узла <book>, который имеет type="SF" в качестве атрибута ....

Чего вы пытаетесь достичь с помощью query(), exist() и value() в одном выражении ??Вполне возможно, это можно сделать намного проще ....

Кроме того: я думаю, что вы неправильно истолковываете то, что делает .exist() в SQL Server XQuery.Если у вас есть выражение здесь:

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

, вы в основном говорите SQL Server извлечь все строки из dbo.TableA, где XML, хранящийся в XMLData, содержит узел <book type=.....> - вы выбираете строкииз таблицы - NOT применение выделения к содержимому столбца XMLData ...

3 голосов
/ 12 декабря 2011

XML-файл, который вы указали, не подходит для оператора exist.Если бы у вас было несколько операторов XML, и вам нужно было найти тот, в котором содержалось бы какое-то значение, то это заявление было бы более уместным.

Введенное вами предложение where просто проверяет, существует ли условие и, если оно существует, выбирает все элементы branches, а не только тот, в котором условие выполняется.Например, следующее (очевидно) ничего не возвращает:

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

Но здесь есть кое-что, чтобы показать, что вы можете использовать все три в одном операторе 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 голосов
/ 01 февраля 2018

С помощью XML более эффективно фильтровать с помощью оператора перекрестного применения, чтобы отфильтровать нужный узел, а затем выбрать запрос из возвращаемых узлов. Для запроса дочерних узлов вам также необходимо включить корень. в запросе, так что в этом случае .// ответвление, а не // ответвление.

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

Вы по-прежнему можете добавить предложение о существовании, если хотите, но это фактически добавит дополнительные ненужные накладные расходы

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

Надеюсь, это поможет. D

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...