SQL-为多个XML结果返回xpath

时间:2018-12-13 00:05:47

标签: sql sql-server xml xpath xquery

我有这个查询:

select XMLMetadata from taObjectMetadata where ObjectMetadataTypeId = 1

返回3000多行,每行包含XML:

<objectMetaData>
  <fileLocation fileName="CM63951.mxf06092018233409;21.png" />
</objectMetaData>

我需要拉出该文件名。我可以使用XQuery轻松地对任何给定的行执行此操作:

declare @x XML = ('<objectMetaData>
  <fileLocation fileName="CM63951.mxf06092018233409;21.png" />
</objectMetaData>')

select x.value(N'@fileName', N'nvarchar(100)') as Filename
from @x.nodes(N'/objectMetaData/fileLocation') t(x)

这正是我所需要的。但是,对于表中的每个XML,我都需要它。尝试将查询放入声明XML中失败,因为它当然会返回多个结果。

我是否需要在此处使用WHILE循环。还是有更好/更优雅的方式来做到这一点?

2 个答案:

答案 0 :(得分:1)

您可以尝试使用CROSS APPLY

select x.value('@fileName', N'nvarchar(100)')  as Filename
FROM yourTable CROSS APPLY yourTable.data.nodes(N'objectMetaData/fileLocation') as t(x)

注意yourTable可以代替您当前的结果集。

您的查询可能是这样的。

select x.value('@fileName', N'nvarchar(100)')  as Filename
FROM (
  select XMLMetadata 
  from taObjectMetadata 
  where ObjectMetadataTypeId = 1
)  t1 CROSS APPLY t1.XMLMetadata.nodes(N'objectMetaData/fileLocation') as t(x)

这里是一个示例:sqlfiddle

答案 1 :(得分:1)

您的问题不清楚,是XML总是像您显示的XML(只是一个<fileLocation>),还是该结构可能包含更多XML。

如果只是一个,问题可能是:为什么使用XML?

无论如何:这是两种情况的模拟场景:

DECLARE @mockup TABLE(ID INT IDENTITY,TheXml XML);

INSERT INTO @mockup VALUES
    ('<objectMetaData>
    <fileLocation fileName="CM63951.mxf06092018233409;21.png" />
    </objectMetaData>')
,('<objectMetaData>
    <fileLocation fileName="OneMore.png" />
    </objectMetaData>')
,('<objectMetaData>
    <fileLocation fileName="TheFirst.png" />
    <fileLocation fileName="TheSecond.png" />
    </objectMetaData>');

您可以直接选择第一个。不需要派生表

--Returns the only (or the first) file name
SELECT m.ID 
        ,TheXml.value('(/objectMetaData/fileLocation/@fileName)[1]','nvarchar(max)')
FROM @mockup m

-如果有多个<fileLocation>节点,则需要通过.nodes()

派生表
--Returns multiple filenames
SELECT m.ID 
        ,fl.value('@fileName','nvarchar(max)')
FROM @mockup m
CROSS APPLY TheXml.nodes('/objectMetaData/fileLocation') A(fl);

因此对于您的实际查询来说,应该是

--for one filename per row
select XMLMetadata.value('(/objectMetaData/fileLocation/@fileName)[1]','nvarchar(max)')
from taObjectMetadata 
where ObjectMetadataTypeId = 1

或这个

--for many filenames per row
select fl.value('@fileName','nvarchar(max)')
from taObjectMetadata 
cross apply XMLMetadata.nodes('/objectMetaData/fileLocation') A(fl)
where ObjectMetadataTypeId = 1