2016-05-02 25 views
0

我有一个表保存xml数据。 xml如下Xml到tsql中的表

<responses> 
    <response> 
    <id>UniqueRowID</id> 
    <value>16</value> 
    </response> 
    <response> 
    <id>Language</id> 
    <value>en-GB</value> 
    </response> 
    <response> 
    <id>UserId</id> 
    <value>21</value> 
    </response> 
</responses> 

在下一列中可以有其他一些数据。价值是所有人共同的价值。但其中一些ID可能不在另一行。

现在我需要一个表格,格式如下。我知道所有列应该显示。如果某个列不在xml中,它可以是空白的。我怎样才能做到这一点?

UniqueRowID语言用户ID

--- ------- ------

16 EN-GB 21

我看到了一些相似,但没有对我的作品,因为xml在这些示例中有不同的表示方式

+0

可以使用SSIS?这是一次性进口吗? – TheNorthWes

+0

我打算通过数据创建一个ssrs报告 –

+0

这不能回答我的问题,但我认为如果这是一个报告,那么您需要重复加载数据。 SSIS是一个选项吗? – TheNorthWes

回答

1

我把这个作为第二个答案,因为它是一个完全不同的方法。有了这个代码,你可以阅读这个结构的任何XML。使用动态SQL能够创建动态的列名:

CREATE TABLE #tmpTbl (YourXml XML); 
INSERT INTO #tmpTbl VALUES 
('<responses> 
    <response> 
    <id>UniqueRowID</id> 
    <value>16</value> 
    </response> 
    <response> 
    <id>Language</id> 
    <value>en-GB</value> 
    </response> 
    <response> 
    <id>UserId</id> 
    <value>21</value> 
    </response> 
    <response> 
    <id>SomeOther1</id> 
    <value>SO1</value> 
    </response> 
    <response> 
    <id>SomeOther2</id> 
    <value>SO2</value> 
    </response> 
</responses>'); 

DECLARE @columnNames VARCHAR(MAX)= 
(
    STUFF(
    (
     SELECT ',[' + B.value('id[1]','varchar(max)')+ ']' 
     FROM #tmpTbl 
     CROSS APPLY YourXml.nodes('/responses/response') AS A(B) 
     FOR XML PATH('') 
    ),1,1,''  
    ) 
); 

DECLARE @cmd VARCHAR(MAX)= 
'SELECT p.* 
FROM 
(
    SELECT B.value(''id[1]'',''varchar(max)'') AS ColumnName 
      ,B.value(''value[1]'',''varchar(max)'') AS ColumnValue 
    FROM #tmpTbl 
     CROSS APPLY YourXml.nodes(''/responses/response'') AS A(B) 
) AS tbl 
PIVOT 
(
    MIN(ColumnValue) FOR ColumnName IN(' + @columnNames + ') 
) As p'; 

EXEC(@cmd); 
GO 

DROP TABLE #tmpTbl; 

结果:

UniqueRowID Language UserId SomeOther1 SomeOther2 
16   en-GB  21  SO1   SO2 
+0

昨天我采用了同样的方式。感谢您的更新。我从第一个答案中获得了数据。我给了枢轴 –

2

这是一个简单的XML结构。如果您需要将它“拼合”到SQL表中,可以使用XPATH语法来完成,如下所示。

declare @xml xml = ' 
<responses> 
    <response> 
    <id>UniqueRowID</id> 
    <value>16</value> 
    </response> 
    <response> 
    <id>Language</id> 
    <value>en-GB</value> 
    </response> 
    <response> 
    <id>UserId</id> 
    <value>21</value> 
    </response> 
</responses> 
'; 
select 
    T.c.value('(id)[1]','nvarchar(100)') as UniqueRowID 
,T.c.value('(value)[1]','nvarchar(100)') as Language 
from 
    @xml.nodes('/responses/response') T(c) 

,这将给你这样的数据:

UniqueRowID | Language 
====================== 
UniqueRowID | 16 
Language | en-GB 
UserId  | 21 

我有点困惑你的意思是,当你写:

在下一栏也可以有一些其他数据。价值是所有人共同的价值。但其中一些ID可能不在另一行。

它似乎也是以一种不太适合XML的方式构造这些数据。理想情况下,每个响应元素都应具有相同的组件。

你可能会考虑更多的东西像这样(只深思):

<responses> 
    <response> 
    <UniqueRowID>100</UniqueRowID> 
    <UserId>16</id> 
    <Language>EN-GB</value> 
    </response> 
    <response> 
    <UniqueRowID>200</UniqueRowID> 
    <UserId>17</id> 
    <Language>ES</value> 
    </response> 
    <response> 
    <UniqueRowID>300</UniqueRowID> 
    <UserId>18</id> 
    <Language>DE</value> 
    </response> 
</responses> 
+0

欣赏努力。但查询将导致2列。我需要3列结果(如果用户选择3列)。在下一列中可以有其他一些数据意味着下一行可能没有userid。相反,它可能有发起者。如果用户选择他对发起人感兴趣,只有lanuguage才会显示这两列仅作为结果 –

+0

xml格式的数据也只在我的情况下才是好的。它实际上以id&value的形式保存了一个关键值对的列表 –

+1

@BineshNambiarC我是否理解正确?你希望所有'response'节点都被视为键/值对,其值为数据,id作为列名在单行中?请检查我的答案...您可以根据需要添加任意数量的列。缺少的将保持空白... – Shnugo

1

试试这样说:

DECLARE @xml XML= 
'<responses> 
    <response> 
    <id>UniqueRowID</id> 
    <value>16</value> 
    </response> 
    <response> 
    <id>Language</id> 
    <value>en-GB</value> 
    </response> 
    <response> 
    <id>UserId</id> 
    <value>21</value> 
    </response> 
</responses>' 

SELECT @xml.value('(/responses/response[id="UniqueRowID"]/value)[1]','int') AS UniqueRowID 
     , @xml.value('(/responses/response[id="Language"]/value)[1]','varchar(max)') AS Language 
     , @xml.value('(/responses/response[id="UserId"]/value)[1]','int') AS UserId 

结果

UniqueRowID Language UserId 
16   en-GB  21