我有以XML格式存储的数据,其格式多于HTML格式,而不是真正的XML格式。元素头包含列名,行元素包含这些列的数据。
<root>
<head>
<value>DeviceID</value>
<value>VolumeName</value>
<value>SizeGB</value>
<value>FreeSpaceGB</value>
<value>FreeSpacePercent</value>
</head>
<row>
<value>C:</value>
<value>c$OS-COMPUTER01</value>
<value>126</value>
<value>43</value>
<value>34</value>
</row>
<row>
<value>D:</value>
<value>D$DB-COMPUTER01</value>
<value>127</value>
<value>104</value>
<value>82</value>
</row>
<row>
<value>E:</value>
<value>E$COMPUTER01</value>
<value>127</value>
<value>106</value>
<value>84</value>
</row>
</root>
这里的问题是,这只是我的收藏品之一。还有其他集合项,它们具有相同的格式,但可能不同的列数,因此我不能将列名硬编码到select语句中。此外,一些值可以为空。 其他收集项目的示例可以在下面找到:
<data>
<head>
<value>FriendlyName</value>
<value>DnsNameList</value>
<value>NotAfter</value>
<value>NotBefore</value>
<value>Thumbprint</value>
<value>Issuer</value>
</head>
<row>
<value />
<value />
<value>08/23/2021 07:59:59</value>
<value>08/23/2011 08:00:00</value>
<value>E1A7D7E3BD6CA0C832182248EF7F092A72F9EB67</value>
<value>CN=Hewlett-Packard Private Class 2 Certification Authority, O=Hewlett-Packard Company, C=US, OU=IT Infrastructure, O=hp.com</value>
</row>
<row>
<value>Microsoft Root Certificate Authority</value>
<value />
<value>05/10/2021 07:28:13</value>
<value>05/10/2001 07:19:22</value>
<value>CDD4EEAE6000AC7F40C3802C171E30148030C072</value>
<value>CN=Microsoft Root Certificate Authority, DC=microsoft, DC=com</value>
</row>
<row>
<value>Thawte Timestamping CA</value>
<value />
<value>01/01/2021 07:59:59</value>
<value>01/01/1997 08:00:00</value>
<value>BE36A4562FB2EE05DBB3D32323ADF445084ED656</value>
<value>CN=Thawte Timestamping CA, OU=Thawte Certification, O=Thawte, L=Durbanville, S=Western Cape, C=ZA</value>
</row>
<row>
<value>Microsoft Root Authority</value>
<value />
<value>12/31/2020 15:00:00</value>
<value>01/10/1997 15:00:00</value>
<value>A43489159A520F0D93D032CCAF37E7FE20A8B419</value>
<value>CN=Microsoft Root Authority, OU=Microsoft Corporation, OU=Copyright (c) 1997 Microsoft Corp.</value>
</row>
</data>
我需要能够将具有此结构的数据解析为SQL表,以便将来能够使用它。预期的结果将是SQL表,看起来像这样:
DeviceID VolumeName SizeGB FreeSpaceGB FreeSpacePercent
-------- --------------- ------ ----------- ----------------
C: c$OS-COMPUTER01 126 43 34
D: D$DB-COMPUTER01 127 104 82
E: E$COMPUTER01 127 106 84
目前,我将头数据和行数据解析为临时表,并迭代构建动态SQL代码的各个表,然后执行它以创建另一个表并将解析后的数据插入其中。
--code snippet which parses the rows
SELECT ROW_NUMBER() OVER (ORDER BY (SELECT 1)) n, xx.value('.', 'VARCHAR(MAX)') v INTO #rows
FROM (values(@x)) t1(x)
CROSS APPLY x.nodes('//row/value') t2(xx)
...
--code snippet building the INSERT queries
WHILE (@loopcounter * @columns) < @rows
BEGIN
DECLARE @insertstatement VARCHAR(MAX)
SET @insertstatement = 'INSERT INTO #result VALUES ('
DECLARE @forcounter INT = 1
WHILE @forcounter <= @columns
BEGIN
DECLARE @rownumber int = (@loopcounter * @columns) + @forcounter
SELECT @insertstatement += '''' + REPLACE(v, '''', '''''') + ''', ' FROM #rows WHERE n = @rownumber
SET @forcounter += 1
END
SET @insertstatement = SUBSTRING(@insertstatement, 1, LEN(@insertstatement) - 1)
SET @insertstatement += ')'
EXEC (@insertstatement)
SET @loopcounter += 1
END
...
我搜索了这个论坛,但还没找到解决方案,它可以动态地使用以这种方式存储的列名。你能告诉我们可以做些什么吗?
答案 0 :(得分:1)
以下查询将以非透视格式检索所有数据:
DECLARE @xml XML=
'<root>
<head>
<value>DeviceID</value>
<value>VolumeName</value>
<value>SizeGB</value>
<value>FreeSpaceGB</value>
<value>FreeSpacePercent</value>
</head>
<row>
<value>C:</value>
<value>c$OS-COMPUTER01</value>
<value>126</value>
<value>43</value>
<value>34</value>
</row>
<row>
<value>D:</value>
<value>D$DB-COMPUTER01</value>
<value>127</value>
<value>104</value>
<value>82</value>
</row>
<row>
<value>E:</value>
<value>E$COMPUTER01</value>
<value>127</value>
<value>106</value>
<value>84</value>
</row>
</root>';
- 查询
WITH ColumnNames AS
(
SELECT ROW_NUMBER() OVER(ORDER BY (SELECT NULL)) AS ColumnInx
,c.value(N'text()[1]','nvarchar(max)') AS ColumnName
FROM @xml.nodes(N'/root/head/value') AS A(c)
)
,TheRows AS
(
SELECT ROW_NUMBER() OVER(ORDER BY (SELECT NULL)) AS RowInx
,r.query(N'value') AS TheValues
FROM @xml.nodes(N'/root/row') AS B(r)
)
SELECT r.RowInx
,cn.ColumnInx
,cn.ColumnName
,r.TheValues.value(N'value[sql:column("ColumnInx")][1]','nvarchar(max)') AS row_value
FROM TheRows AS r
CROSS JOIN ColumnNames AS cn;
结果
+--------+-----------+------------------+-----------------+
| RowInx | ColumnInx | ColumnName | row_value |
+--------+-----------+------------------+-----------------+
| 1 | 1 | DeviceID | C: |
+--------+-----------+------------------+-----------------+
| 1 | 2 | VolumeName | c$OS-COMPUTER01 |
+--------+-----------+------------------+-----------------+
| 1 | 3 | SizeGB | 126 |
+--------+-----------+------------------+-----------------+
| 1 | 4 | FreeSpaceGB | 43 |
+--------+-----------+------------------+-----------------+
| 1 | 5 | FreeSpacePercent | 34 |
+--------+-----------+------------------+-----------------+
| 2 | 1 | DeviceID | D: |
+--------+-----------+------------------+-----------------+
| 2 | 2 | VolumeName | D$DB-COMPUTER01 |
+--------+-----------+------------------+-----------------+
| 2 | 3 | SizeGB | 127 |
+--------+-----------+------------------+-----------------+
| 2 | 4 | FreeSpaceGB | 104 |
+--------+-----------+------------------+-----------------+
| 2 | 5 | FreeSpacePercent | 82 |
+--------+-----------+------------------+-----------------+
| 3 | 1 | DeviceID | E: |
+--------+-----------+------------------+-----------------+
| 3 | 2 | VolumeName | E$COMPUTER01 |
+--------+-----------+------------------+-----------------+
| 3 | 3 | SizeGB | 127 |
+--------+-----------+------------------+-----------------+
| 3 | 4 | FreeSpaceGB | 106 |
+--------+-----------+------------------+-----------------+
| 3 | 5 | FreeSpacePercent | 84 |
+--------+-----------+------------------+-----------------+
如果您需要表格格式,则可以使用动态创建的PIVOT
命令完成此操作。 Here is one example如何做到这一点。