如何在 SQL 中查询特定文本的 xml 列

Posted

技术标签:

【中文标题】如何在 SQL 中查询特定文本的 xml 列【英文标题】:How to query xml column in TSQL for specific text 【发布时间】:2018-05-04 04:27:18 【问题描述】:

我正在尝试从以下 XML 文档中查询单词 Simple。 列是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>

不确定这是否对如何查询有任何影响。

任何帮助将不胜感激。

【问题讨论】:

【参考方案1】:

了解您想从 XML 中挑选出哪些内容非常重要。有 elementsattributes - 以及元素标签之间的浮动 texttext() 节点。执行这个看看原理:

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/Folder/Authorization[@Mode="Simple"]')

这将返回属性“Mode”的内容为“Simple”的所有&lt;Authorization&gt; 节点(xml 类型!)

选择 @xml.value('(/InstanceSecurity/Folder/Authorization/@Mode)[1]','nvarchar(100)') (你忘了“模式”之前的@!)

这将返回属性的值。在上述情况下,这是“简单”

关于您的问题

我真的不知道你想要什么,但以下其中一项应该为你指明方向

--返回给定路径@Mode属性的第一个值

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

--如果您的 XML 可能包含多个 &lt;Authorization&gt;,这将返回它们的所有 @Mode 属性

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

--这将返回 - 在很多情况下 - 所有 &lt;Authorization&gt; 元素,其中 @Mode 为“简单”

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

--这将返回所有表的行,其中至少一个@Mode 的值为“Simple”

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

最终提示:您可以将XQuery 中的文字值替换为sql:variable("@VarName")sql:column("ColumnName")

【讨论】:

谢谢Shnugo,我只是在学习XML,对所有的部分/部分还没有很好的了解,还在读这本书。我的最终目标是找出哪些案例是安全的,这样我就不会将它们包含在我的 s-s-rS 报告中。安全案例具有类似于我上面示例的 XML,不安全案例具有以下 XML,,我能够读取拒绝标签的存在,这告诉我案件是安全的。但我想读简单这个词,不知道怎么做。【参考方案2】:

试试这个

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

【讨论】:

我不认为,这确实是 OP 所需要的。如果这是正确的回报,您应该使用XML.exist()。您的方法必须切碎每个 XML,只是为了在最后过滤掉大部分....exist() 针对性能进行了优化... @Shnugo 我总是从XMLs 中查询一个特定的值,并且不熟悉这种方法。很高兴知道这一点,谢谢:)

以上是关于如何在 SQL 中查询特定文本的 xml 列的主要内容,如果未能解决你的问题,请参考以下文章

本机查询 - 如何仅从数据库中检索实体的特定列

如何提高下面提到的 SQL 查询中的文本列性能

如何修改此 SQL 查询中的 XML 代码以突出显示表的特定行?

查询列的 SQL 连接问题

SQL查询从特定列中的每个字段中删除某些文本 - Oracle SQL

如何从常规 SQL 查询中输出 XML?