Sql server TSQL XQuery筛选器仅选择包含至少一个字符(或非数字)的节点

Sql 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

<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