SQL - вернуть xpath для нескольких результатов XML - PullRequest
0 голосов
/ 13 декабря 2018

У меня есть этот запрос:

select XMLMetadata from taObjectMetadata where ObjectMetadataTypeId = 1

, который возвращает 3000+ строк, каждая строка, содержащая XML:

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

Мне нужно вытащить это fileName из,Я могу сделать это для любой строки достаточно легко с помощью 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 голосов
/ 13 декабря 2018

Ваш вопрос не проясняет, является ли XML всегда похожим на тот, который вы показываете (только один <fileLocation>), или эта структура может содержать больше.

Если это только один может возникнуть вопрос: почему 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
0 голосов
/ 13 декабря 2018

Вы можете попытаться использовать 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

...