如何在 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 中挑选出哪些内容非常重要。有 elements 和 attributes - 以及元素标签之间的浮动 text,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/Folder/Authorization[@Mode="Simple"]')
这将返回属性“Mode”的内容为“Simple”的所有<Authorization>
节点(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 可能包含多个 <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
的值为“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,试试这个
SELECT * FROM Cases
WHERE InstanceSecurity.value('(/InstanceSecurity/Folder/Authorization/@Mode)[1]','varchar(100)') = 'Simple'
【讨论】:
我不认为,这确实是 OP 所需要的。如果这是正确的回报,您应该使用XML.exist()
。您的方法必须切碎每个 XML,只是为了在最后过滤掉大部分....exist()
针对性能进行了优化...
@Shnugo 我总是从XML
s 中查询一个特定的值,并且不熟悉这种方法。很高兴知道这一点,谢谢:)以上是关于如何在 SQL 中查询特定文本的 xml 列的主要内容,如果未能解决你的问题,请参考以下文章
如何修改此 SQL 查询中的 XML 代码以突出显示表的特定行?