在SQL Server中检索具有相同前缀的所有XML元素

在SQL Server中检索具有相同前缀的所有XML元素,sql,sql-server,xml,tsql,xquery-sql,Sql,Sql Server,Xml,Tsql,Xquery Sql,我有一个XML文件,其格式类似于: <XML> <Field1>100</Field1> <Field2>200</Field2> <Field3>300</Field3> <Test>400</Test> </XML> 我尝试了以下方法,但无效: Select xc.value('text()', 'int') From @XML

我有一个XML文件,其格式类似于:

<XML>
   <Field1>100</Field1>
   <Field2>200</Field2>
   <Field3>300</Field3>
   <Test>400</Test>
</XML>
我尝试了以下方法,但无效:

Select 
    xc.value('text()', 'int')
From 
    @XMLData.nodes('/XML/[starts-with(name(), ''Field'')]') As xt(xc)
注意:我很清楚,如果我重新格式化XML,这项任务可以很容易完成,但不幸的是,我无法控制XML的格式。

一种方法是

declare @XMLData xml ='<XML>
   <Field1>100</Field1>
   <Field2>200</Field2>
   <Field3>300</Field3>
   <Test>400</Test>
</XML>'

Select 
    xc.value('.', 'int')
From @XMLData.nodes('/XML/*') As xt(xc)
WHERE xc.value('local-name(.)', 'varchar(50)') LIKE 'Field%'

使用特殊字符作为名称前缀,并改为选中包含

declare @x xml ='<XML>
   <Field1>100</Field1>
   <Field2>200</Field2>
   <Field3>300</Field3>
   <Test>400</Test>
</XML>';

select t.n.value('.','varchar(100)')
from @x.nodes ('XML/*[contains(concat("$",local-name()),"$Field")]') t(n);

我想这就是你想要的:

DECLARE @xml XML=
'<XML>
   <Field1>100</Field1>
   <Field2>200</Field2>
   <Field3>300</Field3>
   <Test>400</Test>
</XML>';

SELECT Fld.value('.','int') AS FieldOnly
FROM @xml.nodes('/XML/*[substring(local-name(.),1,5)="Field"]') AS A(Fld)

将第一行更改为区分测试用例!,你只会得到一排400

如果您想获得以字段开头的值,那么您的预期输出如何包含400?@techspider Ah是的,这是一个很好的观点。那是我的错误。我更新了我的预期输出。这正是我所需要的。我不知道您可以在where子句中使用该值。我还没有看到这样做的例子。多谢各位@在这样一个小的XML中使用pagspi这是绝对可以的,但是在更大的结构或很多结构中,我更喜欢这样一种方法,即您不必读取所有数据,只是在之后对其进行过滤。在我看来,您尝试在XQuery中放置过滤器的效果更好…@Shnugo:SQL中的XML处理通常比关系处理的性能差。在这种情况下,我甚至不敢打赌在XML内部还是外部进行过滤会更好。我要说的是,所有的解决方案都是可行的,除非测量结果表明并非如此。而且SQL中的XQuery在函数方面非常有限,所以一些过滤甚至是不可能的。@Jeroenmoster,关于性能的另一个想法。。。对于一个包含数百个节点的XML,并且它来自一个包含许多行的表,我敢打赌a.nodes'/root/*'和一个late WHERE在本地名称上进行筛选。情况会更糟。这仅仅是因为性能糟糕的XML引擎必须读取许多不需要的节点,最后才扔掉这些节点。像这样的一个小例子,它没有任何明显的区别。。。但是早期缩减是一个非常普遍的原则…@Shnugo:XML引擎读取所有这些节点以过滤它们,它无法优化过滤函数。接下来的问题是,向关系引擎输出不必要的值是否比应用过滤器函数更为昂贵,而且我没有数字。我希望早期过滤也会更快,但正如我所说的,我不会就此下注。你说得很对,一般来说,你希望过滤尽可能接近源代码。这似乎是一种很好的方式+1使用字符串长度字段替换5会使代码更加明显。尽管如此,它还是痛苦地证明了所支持的XQuery方言的局限性。谢谢@Shnugo,这个解决方案也很有效,它在XQuery中处理所有问题,这样我就不必加载整个XML和过滤器了。@Jeroenmoster,如果这个字段是硬编码的,我就看不到它的优势了。你会发现文字的两倍。。。。如果动态地需要,可以使用变量并使用let$var:=…、字符串长度和sql:variable@varName要全面了解这一点:-优点是您不必解释或手动计算5。魔法常数总是不确定的。在本例中,如果您决定改为匹配字段,那么忘记更新5要比忘记更新字段的两个实例更容易。
DECLARE @xml XML=
'<XML>
   <Field1>100</Field1>
   <Field2>200</Field2>
   <Field3>300</Field3>
   <Test>400</Test>
</XML>';

SELECT Fld.value('.','int') AS FieldOnly
FROM @xml.nodes('/XML/*[substring(local-name(.),1,5)="Field"]') AS A(Fld)
DECLARE @fldName VARCHAR(100)='Field';
SELECT Fld.value('.','int') AS FieldOnly
FROM @xml.nodes('/XML/*[substring(local-name(.),1,string-length(sql:variable("@fldName")))=sql:variable("@fldName")]') AS A(Fld)