Sql server TSQL XQuery筛选器仅选择包含至少一个字符(或非数字)的节点
我有以下XMLSql server TSQL XQuery筛选器仅选择包含至少一个字符(或非数字)的节点,sql-server,tsql,xpath,xquery,Sql Server,Tsql,Xpath,Xquery,我有以下XML <XML> <Data> <Outer> <Inner>123ABC</Inner> </Outer> <Outer> <Inner>123</Inner> </Outer> <Outer>
<XML>
<Data>
<Outer>
<Inner>123ABC</Inner>
</Outer>
<Outer>
<Inner>123</Inner>
</Outer>
<Outer>
<Inner>-123</Inner>
</Outer>
</Data>
</XML>
查询选择所有节点,即,123ABC
、-123
和123
。但是,我只想选择123ABC
。为了使这一点适用于我的真实示例,我需要调整外部应用
行:
OUTER APPLY @xml.nodes('Data/Outer/Inner') AS Data(h)
我非常确信,我的目标可以通过应用如下过滤器来实现
DECLARE @string NVARCHAR(MAX);
DECLARE @xml XML;
SET @string =
'<XML><Data><Outer><Inner>123ABC</Inner></Outer><Outer><Inner>-123</Inner></Outer><Outer><Inner>123</Inner></Outer></Data></XML>';
SET @xml = @string;
SELECT @xml;
SELECT h.value('text()[1]', 'nvarchar(max)')
FROM @xml.nodes('XML') AS Statements(nodes)
OUTER APPLY @xml.nodes('Data/Outer/Inner') AS Data(h)
@xml.nodes('Data/Outer/Inner[FILTER]')
然而,我找不到任何有效的方法
更新:过滤标准可以详细说明如下。只应显示包含至少一个字母的元素。因此,也不应显示以下值,例如:-1.5、1.5、-33如果您的XML数据实际上是指以下内容(请注意示例中缺少的结尾XML
标记):
123ABC
123
然后,您可以使用类似于表达式的来检查它是否具有非数值的字符:
SELECT X.I.value('text()[1]','varchar(6)') AS [Inner]
FROM @xml.nodes('/XML/Data/Outer/Inner') AS X(I)
WHERE X.I.value('text()[1]','varchar(6)') LIKE '%[^0-9]%'
如果您提供的XML是正确的,您将无法使用XQUERY,因为它不是有效的XML,因为XML
节点未关闭
编辑:基于评论的一些猜测(目标仍然有点不清楚),但是,也许:
SELECT X.I.value('text()[1]','varchar(6)') AS [Inner]
FROM @xml.nodes('/XML/Data/Outer/Inner') AS X(I)
WHERE TRY_CONVERT(decimal(38,0),X.I.value('text()[1]','varchar(6)')) IS NULL;
或者,根据“字母中的字符”这句话,简单地说:
也许你可以试试这样的东西:
//Inner[not(.>0)]/text()
输出“123ABC”。可能就这么简单:
DECLARE @xml XML=
'<XML>
<Data>
<Outer>
<Inner>123ABC</Inner>
</Outer>
<Outer>
<Inner>-123</Inner>
</Outer>
<Outer>
<Inner>-123 with blah</Inner>
</Outer>
<Outer>
<Inner>1.23</Inner>
</Outer>
<Outer>
<Inner>123</Inner>
</Outer>
<Outer>
<Inner>-1.5</Inner>
</Outer>
<Outer>
<Inner>-33</Inner>
</Outer>
</Data>
</XML>';
简而言之:
- 我们使用
.nodes()
检索
元素的派生集
- 但我们添加了一个谓词:我们只查找元素,如果它们的内容不能强制转换为浮动。在本例中,XQuery强制转换为
空()
更新
感谢@lptr的提示,我想补充的是,1.E+2
的值在非常特殊的情况下可能会干扰这一点(由于科学记数法)。但您可以使用转换为十进制的方式:
select cast('1.E+2' as xml).query('.[empty(. cast as xs:float?)]') AS CanBeCastedThereforeEmpty
,cast('1.E+2' as xml).query('.[empty(. cast as xs:decimal?)]') AS CannotBeCastedReturnedAsString
你能解释一下这到底是怎么回事吗?它仅选择值不大于0的节点。这意味着选择了字母数字值。但是负数也会被选择对吗?也许这会更好:[not(.>0)][not(.It计算并选择内容不高于0的内部节点(返回false到测试中)。如果你有负数,则命题为yes。或者//internal[not](.>0或。我现在关闭了XML节点。这是一个输入错误。结果中也有负数。我将此添加到了我的问题中。您能否增强您的解决方案以同时排除负数?知道这是一种情况会有所帮助,@beta。小数(例如7.5
)呢?提供所有场景有助于我们帮助您。我知道。抱歉。之前没有想到这一点。规则应该是:只显示字母数字值。因此,至少包含一个字母的值。7.5
不应在结果集中。科学记法可能会导致冲突(取决于要求):select cast('1.E+2'作为xml).query('.[empty(number())]')
@lptr,这是真的…谢谢提示…使用.cast as xs:decimal?
这似乎很有效…很好!!另一种方法是检查大写()和小写()之间的不相等性…选择cast('1.1A2'作为xml)。query('.[大写(.)一个小写(.)'))(尽管字符串中的标点符号仍然是问题的灰色区域)字母的另一个过滤选项:@ XML节点('/XML/Dea/Out/In[上文(?)NE小写(?)])
SELECT numericInner.value('.','varchar(100)')
FROM @xml.nodes('/XML/Data/Outer/Inner[empty(. cast as xs:float?)]') A(numericInner);
select cast('1.E+2' as xml).query('.[empty(. cast as xs:float?)]') AS CanBeCastedThereforeEmpty
,cast('1.E+2' as xml).query('.[empty(. cast as xs:decimal?)]') AS CannotBeCastedReturnedAsString