如何将XML行转换为列

时间:2018-10-03 14:24:05

标签: sql sql-server xml

我已经看到了一些有关如何将行转换为列的答案,但是它们是特定于问题的,因此我很难转换成自己的解决方案。

数据以varchar开头,但我将其转换为XML,因为我认为这样将其转换为列会更容易。

-- get xml
DECLARE @x XML

SET @x = '<ul><li>Gas grill rotisserie</li><li>Fits the Genesis E-300 gas grill</li><li>Fits the Genesis S-300 gas grill</li><li>Includes a heavy-duty electric motor</li><li>Counterbalance for smooth turning and less motor wear</li></ul>'

SELECT x.r.value('node()[1]','varchar(200)')
FROM @x.nodes('/ul/li') AS x(r)

这将返回如下结果;但是,我现在需要将每一行转换为一列。

enter image description here

我已经尝试过使用数据透视和动态SQL进行变体,但是距离还很远。 如何将每一行转换为一列(当行数未知时)。

参考Convert Rows to columns using 'Pivot' in SQL Server 参考How to convert row values to columns with dynamic columns count?

1 个答案:

答案 0 :(得分:1)

这次我正准备好帮助自己:)...下面的查询接收HTML,将其转换为XML,定义列名并在执行动态SQL之前编写动态SQL。

最终结果是:

enter image description here

DECLARE @x XML,
 @limit int = 4,
 @ItemId NVARCHAR(10) = '11158',
 @cols AS NVARCHAR(MAX),
 @query  AS NVARCHAR(MAX)

-- get xml
SELECT @x = '<ul><li>Gas grill rotisserie</li><li>Fits the Genesis E-300 gas grill</li><li>Fits the Genesis S-300 gas grill</li><li>Includes a heavy-duty electric motor</li><li>Counterbalance for smooth turning and less motor wear</li></ul>'

-- convert rows to columns
select @cols = STUFF((SELECT distinct ',' + QUOTENAME(name) 
                    from
                    (
                      SELECT top (@limit)
                        bar.value('local-name(.)','VARCHAR(12)') + cast(row_number() over(order by bar.value('./.','VARCHAR(10)') asc) as varchar(10)) as name,  
                        bar.value('./.','VARCHAR(255)') as value 
                        FROM
                        @x.nodes('/ul/*') AS foo(bar) 
                    ) d
            FOR XML PATH(''), TYPE
            ).value('.', 'NVARCHAR(MAX)') 
        ,1,1,'')

-- create dynamic sql
set @query = '
            -- get xml
                DECLARE @x XML
                SELECT @x = ''<ul><li>Gas grill rotisserie</li><li>Fits the Genesis E-300 gas grill</li><li>Fits the Genesis S-300 gas grill</li><li>Includes a heavy-duty electric motor</li><li>Counterbalance for smooth turning and less motor wear</li></ul>''
            SELECT ' + @cols + ' 
             from 
             (
               SELECT
                bar.value(''local-name(.)'',''VARCHAR(12)'') + cast(row_number() over(order by bar.value(''./.'',''VARCHAR(10)'') asc) as varchar(10)) as name,  
                bar.value(''./.'',''VARCHAR(255)'') as value 
                FROM
                @x.nodes(''/ul/*'') AS foo(bar) 
            ) x
            pivot 
            (
                max(value)
                for name in (' + @cols + ')
            ) p '

execute sp_executesql @query;