2012-02-08 14 views
6

मैं SQL Server 2008 का उपयोग कर रहा हूं।
कार्य: एक XML फ़ाइल लें और इसे एक (एन) SQL तालिका में पार्स करें।
समस्या: एक्सएमएल के आधार पर कॉलम और उनके नामों की संख्या अलग-अलग होगी।मैं एक XML फ़ाइल से SQL तालिका कैसे बना सकता हूं जिसमें गतिशील संख्या नोड्स होंगी?

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>' 

ऊपर XML का उपयोग उदाहरण के लिए, मैं एक एसक्यूएल तालिका की आवश्यकता होगी कि इस प्रकार दिखाई देगा दिखाई::

table snapshot

यहाँ कैसे मैं ऊपर हो गया है

यहाँ कुछ कोड है तालिका:

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)) 

अब मान लें कि एक्सएमएल बदल गया है जहां प्रत्येक आइटम नोड के पास 'new_node' नाम के साथ एक नया बच्चा नोड था। इसलिए जैसा:

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)) 

इस तालिका प्राप्त करने के लिए:

<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> 

मैं नए नोड शामिल करने के लिए मेरी कोड में परिवर्तन करना होगा

second table from XML

तो समस्या यह है कि बच्चे नोड्स है 'आइटम' का अलग-अलग होगा।

कॉलम निर्दिष्ट किए बिना मैं एक ही टेबल कैसे उत्पन्न कर सकता हूं? क्या OPENXML का उपयोग करने से कुछ और दृष्टिकोण है?

+1

बस उत्सुक, एक्सएमएल से एसक्यूएल टेबल बनाने की आवश्यकता क्यों है, क्योंकि एक्सएमएल को स्टोर करने के विरोध में? एसक्यूएल टेबल के साथ आप कॉलम के अज्ञात सेट के साथ क्या करेंगे जो आप एक्सएमएल डेटा प्रकार में संग्रहीत एक्सएमएल के साथ नहीं कर पाएंगे? –

+0

यह पूछने की तरह है, अगर मैं नहीं जानता कि मुझे कितने बेडरूम चाहिए तो मैं घर कैसे बना सकता हूं? –

+0

माइकल फ्रेड्रिकसन: मैं _will_ एक्सएमएल संग्रहित कर रहा हूं, यह सिर्फ एक सरलीकृत उदाहरण है, लेकिन अंत में तालिका को कोड-बैक पेज पर वापस कर दिया जाएगा जो एक HTML तालिका –

उत्तर

10

कॉलम की एक गतिशील संख्या के साथ आपको गतिशील एसक्यूएल की आवश्यकता है।

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

मुझे लगता है कि यह कभी भी देखा गया है कि टीएसक्यूएल/एक्सएमएल चालबाजी के सबसे अच्छे बिट्स में से एक है, और यह मेरी समस्या हल - ब्रावो – MrTelly

1

माइकल के जवाब में सुधार लाने:

स्तंभों की एक गतिशील संख्या के साथ

आप गतिशील एसक्यूएल की जरूरत है। यह कोड अलग-अलग नोड सूचियों वाले आइटम समेत अज्ञात संख्या के नोड्स का समर्थन करने वाले एक चुनिंदा कथन का निर्माण करेगा।

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; 
संबंधित मुद्दे