Как запросить столбец XML в TSQL для конкретного текста - PullRequest
0 голосов
/ 04 мая 2018

Я пытаюсь запросить слово Simple в следующем XML-документе. Столбец имеет тип данных xml, имя столбца: InstanceSecurity.

.
<InstanceSecurity>
  <Folder>
    <Authorization Mode="Simple">
      <Deny PrivilegeCode="Create" />
      <Deny PrivilegeCode="Delete" />
      <Deny PrivilegeCode="Edit" />
      <Deny PrivilegeCode="Read" />
      <Deny PrivilegeCode="View" />
      <Deny PrivilegeCode="Print" />
      <Allow PrivilegeCode="All" EntityType="Personnel" EntityVal="5bc2" />
      <Allow PrivilegeCode="All" EntityType="Personnel" EntityVal="f85b" />
    </Authorization>
  </Folder>
</InstanceSecurity>

Я пробовал:

Select InstanceSecurity.query('/InstanceSecurity/Folder/Authorization[@Mode="Simple"]') AS SecuredMode
FROM Cases

И

SELECT *
FROM Cases
WHERE InstanceSecurity.value('(/InstanceSecurity/Folder/Authorization/Mode)[1]','nvarchar(100)') like '%'

Никто ничего не возвращает

Большинство примеров, на которые я смотрел, имеют начальный и конечный тег, например

<item id="a">a is for apple</item>

не уверен, влияет ли это на то, как запросить это.

Буду признателен за любую помощь.

Ответы [ 2 ]

0 голосов
/ 04 мая 2018

Очень важно понимать, какой контент вы хотите выбрать из XML. Есть элементы и атрибуты - и плавающий текст между тегами элементов, узел text(). Выполните это, чтобы увидеть принципы:

DECLARE @xml XML=
N'<root>
    <AnElement ID="1" AnAttribute="The attribute''s content">The element''s content</AnElement>
    <AnElement ID="2" AnAttribute="Only the attribute" />
    <AnElement ID="3">Text only</AnElement>
    <AnElement ID="4" AnAttribute="nested children">
        <child>This is the child''s content</child>
        <child>One more child</child>
    </AnElement>
    <AnElement ID="5" AnAttribute="nested children">
        This is text 1 within the element
        <child>This is the child''s content</child>
        This is text 2 within the element
        <child>One more child</child>
        This is text 3 within the element
    </AnElement>
</root>';

SELECT elmt.value(N'@ID',N'int') ID
      ,elmt.value(N'@AnAttribute',N'nvarchar(250)') TheAttribute
      ,elmt.value(N'text()[1]',N'nvarchar(250)') TheFirstText
      ,elmt.value(N'text()[2]',N'nvarchar(250)') TheSecondText
      ,elmt.value(N'child[2]/text()[1]',N'nvarchar(250)') TheFirstTextWithinChild2
      ,elmt.value(N'.',N'nvarchar(250)') AS FullNodeContent
FROM @xml.nodes(N'/root/AnElement') AS A(elmt);

Подсказка: Попробуйте выбрать только последний (value(N'.'),N'nvarchar(250)') и отправить вывод в виде простого текста. Это включает пробелы и переносы строк!

text() (может быть больше text() узлов в одном элементе!) - это просто еще один вид узла , без окружающих тегов.

Ваши попытки (слегка изменены)

Выберите @ Xml.query ( '/ InstanceSecurity / Папка / авторизации [@ Mode = "Simple"]')

Возвращает все <Authorization> узлы (напечатаны в формате xml!), Где атрибут «Mode» имеет содержимое «Simple»

ВЫБРАТЬ @ Xml.value ( '(/ InstanceSecurity / Папка / авторизацию / @ Mode) [1]', 'NVARCHAR (100)')
(Вы забыли @ до «Режима»!)

Возвращает значение атрибута. В приведенном выше случае это «Простой»

О вашей проблеме

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

- возвращает первое значение атрибута @Mode по заданному пути

SELECT InstanceSecurity.value(N'(/InstanceSecurity/Folder/Authorization/@Mode)[1]',N'nvarchar(250)')
FROM Cases;

- Если ваш XML может включать более одного <Authorization>, он вернет все их @Mode атрибуты

SELECT auth.value(N'@Mode',N'nvarchar(250)')
FROM Cases
OUTER APPLY InstanceSecurity.nodes(N'/InstanceSecurity/Folder/Authorization') AS A(auth);

- Возвращает - во многих случаях - все <Authorization> элементов, где @Mode - «Простой»

SELECT auth.query(N'.')
FROM Cases
OUTER APPLY InstanceSecurity.nodes(N'/InstanceSecurity/Folder/Authorization[@Mode="Simple"]') AS A(auth);

- И это возвращает все строки таблицы, где хотя бы одна @Mode имеет значение "Простой"

SELECT *
FROM Cases
WHERE InstanceSecurity.exist(N'/InstanceSecurity/Folder/Authorization[@Mode="Simple"]')=1

Заключительный совет: Вы можете заменить буквальное значение в пределах XQuery на sql:variable("@VarName") или sql:column("ColumnName").

0 голосов
/ 04 мая 2018

Попробуйте это

SELECT * FROM Cases
WHERE InstanceSecurity.value('(/InstanceSecurity/Folder/Authorization/@Mode)[1]','varchar(100)') = 'Simple'
...