2012-02-08 30 views
6

Tôi đang sử dụng SQL Server 2008.
Nhiệm vụ: lấy một tệp XML và phân tích nó thành một bảng SQL (n).
Vấn đề: Số cột và tên của chúng sẽ khác nhau dựa trên XML.Làm cách nào để tạo bảng SQL từ tệp XML có số nút động?

Dưới đây là một số mã:

DECLARE @xmlData XML; 
SET @xmlData = '<root> 
    <item id="1"> 
    <item_number>IT23</item_number> 
    <title>Item number twenty-three</title> 
    <setting>5 to 20</setting> 
    <parameter>10 to 16</parameter> 
    </item> 
    <item id="2"> 
    <item_number>RJ12</item_number> 
    <title>Another item with a 12</title> 
    <setting>7 to 35</setting> 
    <parameter>1 to 34</parameter> 
    </item> 
    <item id="3"> 
    <item_number>LN90</item_number> 
    <title>LN with 90</title> 
    <setting>3 to 35</setting> 
    <parameter>9 to 50</parameter> 
    </item> 
</root>' 

Ví dụ bằng cách sử dụng XML ở trên, tôi sẽ cần một bảng SQL trả về có mà sẽ trông như thế này:

table snapshot

Đây là cách tôi đã nêu trên bảng:

DECLARE @idoc INT; 
    EXEC sp_xml_preparedocument @idoc OUTPUT, @xmlData 

    SELECT * 
    FROM OPENXML (@idoc, '/root/item', 2) 
    WITH (item_number VARCHAR(100), 
     title VARCHAR(100), 
     setting VARCHAR(100), 
     parameter VARCHAR(100)) 

Bây giờ giả sử XML đã thay đổi trong đó mỗi nút mục có một nút con mới với tên 'new_node'. Cũng giống như vậy:

<root> 
    <item id="1"> 
    <item_number>IT23</item_number> 
    <title>Item number twenty-three</title> 
    <setting>5 to 20</setting> 
    <parameter>10 to 16</parameter> 
    <new_node>data</new_node> 
    </item> 
    <item id="2"> 
    <item_number>RJ12</item_number> 
    <title>Another item with a 12</title> 
    <setting>7 to 35</setting> 
    <parameter>1 to 34</parameter> 
    <new_node>goes</new_node> 
    </item> 
    <item id="3"> 
    <item_number>LN90</item_number> 
    <title>LN with 90</title> 
    <setting>3 to 35</setting> 
    <parameter>9 to 50</parameter> 
    <new_node>here</new_node> 
    </item> 
</root> 

tôi phải thay đổi mã của tôi để bao gồm các nút mới:

SELECT * 
    FROM OPENXML (@idoc, '/root/item', 2) 
    WITH (item_number VARCHAR(100), 
     title VARCHAR(100), 
     setting VARCHAR(100), 
     parameter VARCHAR(100), 
     new_node VARCHAR(100)) 

Để có được bảng này:

second table from XML

Vì vậy, vấn đề là các nút con của 'item' sẽ thay đổi.

Làm cách nào để tạo các bảng giống nhau mà không chỉ định các cột? Có cách tiếp cận nào khác ngoài việc sử dụng OPENXML không?

+1

Chỉ cần tò mò, tại sao bạn cần tạo bảng SQL từ XML, trái ngược với việc lưu trữ XML đơn giản? Bạn sẽ làm gì với một bảng SQL với một tập hợp các cột không xác định mà bạn sẽ không thể làm với XML được lưu trữ trong một kiểu dữ liệu XML? –

+0

Điều này giống như yêu cầu, làm thế nào để xây dựng một ngôi nhà nếu tôi không biết có bao nhiêu phòng ngủ tôi cần? –

+0

Michael Fredrickson: Tôi _will_ được lưu trữ XML, đây chỉ là một ví dụ đơn giản, nhưng cuối cùng bảng sẽ được trả về một trang mã phía sau sẽ tạo ra một bảng HTML –

Trả lời

10

Với số cột động bạn cần SQL động.

declare @XML xml = 
'<root> 
    <item id="1"> 
    <item_number>IT23</item_number> 
    <title>Item number twenty-three</title> 
    <setting>5 to 20</setting> 
    <parameter>10 to 16</parameter> 
    <new_node>data</new_node> 
    </item> 
    <item id="2"> 
    <item_number>RJ12</item_number> 
    <title>Another item with a 12</title> 
    <setting>7 to 35</setting> 
    <parameter>1 to 34</parameter> 
    <new_node>goes</new_node> 
    </item> 
    <item id="3"> 
    <item_number>LN90</item_number> 
    <title>LN with 90</title> 
    <setting>3 to 35</setting> 
    <parameter>9 to 50</parameter> 
    <new_node>here</new_node> 
    </item> 
</root>' 

declare @SQL nvarchar(max) = '' 
declare @Col nvarchar(max) = ', T.N.value(''[COLNAME][1]'', ''varchar(100)'') as [COLNAME]' 

select @SQL = @SQL + replace(@Col, '[COLNAME]', T.N.value('local-name(.)', 'sysname')) 
from @XML.nodes('/root/item[1]/*') as T(N) 

set @SQL = 'select '+stuff(@SQL, 1, 2, '')+' from @XML.nodes(''/root/item'') as T(N)' 

exec sp_executesql @SQL, N'@XML xml', @XML 
+2

Tôi nghĩ rằng đây là một trong những bit tốt nhất của TSQL/XML trickery tôi từng chứng kiến, và nó giải quyết được vấn đề của tôi - bravo – MrTelly

1

cải thiện về Mikael của câu trả lời:

Với một số năng động của cột bạn cần SQL động. Mã này sẽ tự động xây dựng một câu lệnh chọn hỗ trợ một số lượng các nút không xác định, bao gồm các mục có các danh sách nút khác nhau.

declare @XML xml = 
'<root> 
    <item id="1"> 
    <item_number>IT23</item_number> 
    <title>Item number twenty-three</title> 
    <setting>5 to 20</setting> 
    <parameter>10 to 16</parameter> 
    <new_node>data</new_node> 
    </item> 
    <item id="2"> 
    <item_number>RJ12</item_number> 
    <title>Another item with a 12</title> 
    <setting>7 to 35</setting> 
    <parameter>1 to 34</parameter> 
    <new_node>goes</new_node> 
    </item> 
    <item id="3"> 
    <item_number>LN90</item_number> 
    <title>LN with 90</title> 
    <setting>3 to 35</setting> 
    <parameter>9 to 50</parameter> 
    <new_node>here</new_node> 
    <unique_node>test</unique_node> 
    </item> 
</root>' 

--build an XML object with the unique list of nodes 
DECLARE @xmlcolumns XML; 
WITH Xml_CTE AS 
(
    SELECT 
     CAST('<' + node.value('fn:local-name(.)', 
      'varchar(100)') + '>' AS varchar(100)) 
     + CAST('</' + node.value('fn:local-name(.)', 
      'varchar(100)') + '>' AS varchar(100)) AS name 
    FROM @xml.nodes('/root/item/*') AS roots(node) 

) 

SELECT @xmlcolumns = (
SELECT CONVERT(XML,name) FROM (
SELECT DISTINCT name 
FROM Xml_CTE 
) a 
FOR XML PATH(''), ROOT('root') 
) 



declare @SQL nvarchar(max) = '' 
declare @Col nvarchar(max) = ', T.N.value(''[COLNAME][1]'', ''varchar(100)'') as [COLNAME]'   

--use the unique column list xml object to build the select statement 
select @SQL = @SQL + replace(@Col, '[COLNAME]', T.N.value('local-name(.)', 'sysname')) 
from @XMLcolumns.nodes('/root/*') as T(N)  

--build the entire query statement, using the original XML object as the data source 
set @SQL = 'select '+stuff(@SQL, 1, 2, '')+' from @XML.nodes(''/root/item'') as T(N)' 

exec sp_executesql @SQL, N'@XML xml', @XML; 
Các vấn đề liên quan