How to query xml column in TSQL for specific text

风流意气都作罢 提交于 2020-07-16 10:39:37

问题


I am trying to query the word Simple out the following XML Document. The column is xml data type, the column name is 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>

I've tried:

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

AND

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

Neither one returns anything

Most examples I have looked at have a start and end tag, like

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

not sure if that has any effect on how to query this.

Any help would be appreciated.


回答1:


It is very important to understand, what content you want to pick out of an XML. There are elements and attributes - and the floating text between element tags, the text() node. Execute this to see the principles:

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);

Hint: Try to pick just the last one (value(N'.'),N'nvarchar(250)') and send the output to plain text. This includes spaces and line breaks!

The text() (there may be more text() nodes within one element!) is just another kind of node, coming without surrounding tags.

Your attempts (slightly changed)

Select @xml.query('/InstanceSecurity/Folder/Authorization[@Mode="Simple"]')

This returns all <Authorization> nodes (xml typed!) where the attribute "Mode" has the content "Simple"

SELECT @xml.value('(/InstanceSecurity/Folder/Authorization/@Mode)[1]','nvarchar(100)')
(You forgot the @ before "Mode"!)

This returns the value of the attribute. In the case above this is "Simple"

About your issue

I do not really know what you want, but one of the following should point you the way

--Returns the first value of attribute @Mode at the given path

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

--If your XML might include more than one <Authorization>, this would return all their @Mode attributes

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

--This returns - in cases of many - all <Authorization> elements where the @Mode is "Simple"

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

--And this returns all table's rows where at least one @Mode has the value "Simple"

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

Final hint: You can replace a literal value within XQuery with sql:variable("@VarName") or with sql:column("ColumnName").




回答2:


Try this

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


来源:https://stackoverflow.com/questions/50167165/how-to-query-xml-column-in-tsql-for-specific-text

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!