С помощью XQuery SQL Server 2005 выберите все узлы с определенным значением атрибута или с этим атрибутом отсутствует

Update: предоставление гораздо более подробного примера.

первые два предложенных решения были прямо в соответствии с тем, что я пытался сказать не сделать. Я не могу знать местоположение, он должен иметь возможность смотреть на все дерево документов. Таким образом, решение по этим строкам ,с/ Books / указанным в качестве контекста, не будет работать:

SELECT x.query('.') FROM @xml.nodes('/Books/*[not(@ID) or @ID = 5]') x1(x)

оригинальный вопрос с лучшим примером:

используя реализацию XQuery SQL Server 2005, мне нужно выберите все узлы в XML-документе только один раз и сохраните их исходную структуру, но только если они не имеют определенного атрибута или этот атрибут имеет определенное значение (передается параметром). Запрос также должен работать со всем XML-документом (ось потомка или собственной личности), а не выбирать на предопределенной глубине.

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

например:

если бы это был XML-код:

    DECLARE @Xml XML
    SET @Xml =
    N'
<Library>
  <Novels>
    <Novel category="1">Novel1</Novel>
    <Novel category="2">Novel2</Novel>
    <Novel>Novel3</Novel>
    <Novel category="4">Novel4</Novel>
  </Novels>
  <Encyclopedias>
    <Encyclopedia>
      <Volume>A-F</Volume>
      <Volume category="2">G-L</Volume>
      <Volume category="3">M-S</Volume>
      <Volume category="4">T-Z</Volume>
    </Encyclopedia>
  </Encyclopedias>
  <Dictionaries category="1">
    <Dictionary>Webster</Dictionary>
    <Dictionary>Oxford</Dictionary>
  </Dictionaries>
</Library>
    '

параметр 1 для категории приведет к этому:

<Library>
  <Novels>
    <Novel category="1">Novel1</Novel>
    <Novel>Novel3</Novel>
  </Novels>
  <Encyclopedias>
    <Encyclopedia>
      <Volume>A-F</Volume>
    </Encyclopedia>
  </Encyclopedias>
  <Dictionaries category="1">
    <Dictionary>Webster</Dictionary>
    <Dictionary>Oxford</Dictionary>
  </Dictionaries>
</Library>

параметр 2 для категории приведет к следующему:

<Library>
  <Novels>
    <Novel category="2">Novel2</Novel>
    <Novel>Novel3</Novel>
  </Novels>
  <Encyclopedias>
    <Encyclopedia>
      <Volume>A-F</Volume>
      <Volume category="2">G-L</Volume>
    </Encyclopedia>
  </Encyclopedias>
</Library>

Я знаю, что XSLT идеально подходит для этой работы, но это не вариант. Мы должны полностью выполнить это в SQL Server 2005. Любые реализации, не использующие XQuery, тоже хороши, если это можно сделать полностью в T-SQL.

2 ответов


мне не ясно из вашего примера, чего вы на самом деле пытаетесь достичь. Вы хотите вернуть новый XML со всеми узлами, за исключением тех, которые выполняют условие? Если да, то это похоже на задание для преобразования XSLT, которое я не думаю, что оно встроено в MSSQL 2005 (может быть добавлено как UDF: http://www.topxml.com/rbnews/SQLXML/re-23872_Performing-XSLT-Transforms-on-XML-Data-Stored-in-SQL-Server-2005.aspx).

Если вам просто нужно верните список узлов, тогда вы можете использовать это выражение:

//Book[not(@ID) or @ID = 5]

но у меня такое впечатление, что это не то, что вам нужно. Было бы неплохо, если бы вы привели более ясный пример.

редактировать: этот пример действительно более ясен. Лучшее, что я смог найти это:

SET @Xml.modify('delete(//*[@category!=1])')
SELECT @Xml

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

изменить имеет некоторые ограничения-кажется, вы не можете использовать его в инструкции select, он должен изменять данные на месте. Если вам нужно вернуть такие данные с помощью select, вы можете использовать временную таблицу для копирования исходных данных, а затем обновить эту таблицу. Что-то вроде этого:--6-->
INSERT INTO #temp VALUES(@Xml)
UPDATE #temp SET data.modify('delete(//*[@category!=2])')

надеюсь, что это поможет.


вопрос не совсем ясен, но это то, что вы ищете?

DECLARE @Xml AS XML
        SET @Xml =
        N'
        <Books>
                <Book ID="1">Book1</Book>
                <Book ID="2">Book2</Book>
                <Book ID="3">Book3</Book>
                <Book>Book4</Book>
                <Book ID="5">Book5</Book>
                <Book ID="6">Book6</Book>
                <Book>Book7</Book>
                <Book ID="8">Book8</Book>
        </Books>
        '
DECLARE @BookID AS INT
SET @BookID = 5
DECLARE @Result AS XML

SET @result = (SELECT @xml.query('//Book[not(@ID) or @ID = sql:variable("@BookID")]'))
SELECT @result