Преобразование повторяющихся значений узлов xml из столбца xml в #table путем повторения по идентификатору таблицы - PullRequest
1 голос
/ 09 июля 2020

Для следующей структуры таблицы:

LibraryID(INT)  XMLData(NVARCHAR(MAX))
-----------     --------------------
1               <Library xmlns:xsi="http:...
2               <Library xmlns:xsi="http:...
3               <Library xmlns:xsi="http:...

XMLData, где TableID = 1, содержит такие значения, как:

<Library xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
    <Books>
        <LibraryBook>
            <Author>Author 1</Author>
            <Title>Title 1</Title>
        </LibraryBook>
        <LibraryBook>
            <Author>Author 2</Author>
            <Title>Title 2</Title>
        </LibraryBook>
        <LibraryBook>
            <Author>Author 3</Author>
            <Title>Title 3</Title>
        </LibraryBook>
    </Books>
    <Magazines>
    ...
    </Magazines>
</Library>  

Я бы хотел, чтобы результат был:

LibraryID(INT)  Author      Title
-----------     ---------   -------
1               Author 1    Title 1
1               Author 2    Title 2
1               Author 3    Title 3
2               ...         ...
3               ...         ...  
3               ...         ...

Я пробовал выполнить следующий запрос:

;WITH XmlData AS
(
    SELECT
        LibraryID,
        XmlNodes = CAST(XmlData AS XML)
    FROM
        Library
)
,BrokenDown AS
(
    SELECT 
        LibraryID, 
        Author = XmlNodes.value('(/Library/Books/LibraryBook/Author)[1]', 'VARCHAR(100)'),
        Title = XmlNodes.value('(/Library/Books/LibraryBook/Title)[1]', 'VARCHAR(100)')
    FROM 
        XmlData
)

SELECT * FROM BrokenDown

В выводе указаны только первая книга и название для каждого идентификатора библиотеки:

LibraryID    Author      Title
---------    ------      -----
1            Author 1    Title 1
2            ...         ...
3            ...         ...

Любая помощь будет принята с благодарностью .

Ответы [ 2 ]

2 голосов
/ 09 июля 2020

После того, как вы «очистили» свой XML (конечные теги </FieldName> и </DisplayIndex> не совпадают с начальными тегами <Author> и <Title> ....) - и как только вы ' вы определили свой столбец как XML (поскольку он не содержит ничего, кроме XML - почему он изначально не объявлен как XML ???) - вы можете попробовать это:

SELECT
    LibraryID,
    Author = XC.value('(Author/text())[1]', 'varchar(50)'),
    Title = XC.value('(Title/text())[1]', 'varchar(50)')
FROM
    dbo.Library
CROSS APPLY
    XmlData.nodes('/Library/Books/LibraryBook') AS XT(XC)

Если вы должны сохранить не очень полезный NVARCHAR(MAX) тип данных - тогда вам нужно, чтобы CTE «преобразовать в XML» опережал SELECT, например:

;WITH XmlCte AS 
(
    SELECT 
        LibraryId, 
        RealXmlData = CAST(XmlData AS XML)
    FROM dbo.Library
)
SELECT
    LibraryId,
    Author = XC.value('(Author/text())[1]', 'varchar(50)'),
    Title = XC.value('(Title/text())[1]', 'varchar(50)')
FROM
    RealXmlData
CROSS APPLY
    XmlData.nodes('/Library/Books/LibraryBook') AS XT(XC)

Обновление: добавил выражения /text() к обоим элементам XML, выбранным в XQuery - спасибо @YitzhakKhabinsky за этот совет - значительно ускоряет запрос!

2 голосов
/ 09 июля 2020

Примерно так:

use tempdb
go
drop table if exists Library
go

create table Library(LibraryId int identity primary key, XmlData xml)

go

insert into Library(XmlData)
values 
('<Library xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
    <Books>
        <LibraryBook>
            <Author>Author 1</Author>
            <Title>Title 1</Title>
        </LibraryBook>
        <LibraryBook>
            <Author>Author 2</Author>
            <Title>Title 2</Title>
        </LibraryBook>
        <LibraryBook>
            <Author>Author 3</Author>
            <Title>Title 3</Title>
        </LibraryBook>
    </Books>
    <Magazines>
    ...
    </Magazines>
</Library>  '
),
('<Library xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
    <Books>
        <LibraryBook>
            <Author>Author 1</Author>
            <Title>Title 1</Title>
        </LibraryBook>
        <LibraryBook>
            <Author>Author 2</Author>
            <Title>Title 2</Title>
        </LibraryBook>
        <LibraryBook>
            <Author>Author 3</Author>
            <Title>Title 3</Title>
        </LibraryBook>
    </Books>
    <Magazines>
    ...
    </Magazines>
</Library>  '
),
('<Library xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
    <Books>
        <LibraryBook>
            <Author>Author 1</Author>
            <Title>Title 1</Title>
        </LibraryBook>
        <LibraryBook>
            <Author>Author 2</Author>
            <Title>Title 2</Title>
        </LibraryBook>
        <LibraryBook>
            <Author>Author 3</Author>
            <Title>Title 3</Title>
        </LibraryBook>
    </Books>
    <Magazines>
    ...
    </Magazines>
</Library>  '
)

select l.LibraryId, 
       book.value('(Author)[1]','varchar(20)') Author, 
       book.value('(Title)[1]','varchar(20)') Title 
from Library l
outer apply l.XmlData.nodes('Library/Books/LibraryBook') books(book)

выходы

LibraryId   Author               Title
----------- -------------------- --------------------
1           Author 1             Title 1
1           Author 2             Title 2
1           Author 3             Title 3
2           Author 1             Title 1
2           Author 2             Title 2
2           Author 3             Title 3
3           Author 1             Title 1
3           Author 2             Title 2
3           Author 3             Title 3

(9 rows affected)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...