2017-03-16 100 views
1

我有一個表:文本XML到SQL表...有,然後再返回

with XMLData as (
    SELECT uid, commonname, cast(labeldetails as XML) labelxml 
    FROM [MyLables] 
) 
SELECT 
    uid 
    ,commonname 
    ,labelxml 
FROM 
    XMLData [x] 

我得到(濃縮爲簡單起見):

B8A3DF5E OrderType1 <NewDataSet><LabelData><Name>1d Vert</Name><Column>... 
9D0F94C7 OrderType2 <NewDataSet><LabelData><Name>ItemNumber1D</Name><Co... 

內標籤詳情是XML數據

<NewDataSet> 
    <LabelData> 
     <Name>mol</Name> 
     <Column>mol</Column> 
     <Type>MOLIMAGE</Type> 
     <xpos>510</xpos> 
     <ypos>110</ypos> 
     <width>auto</width> 
     <height>auto</height> 
     <Font>Arial</Font> 
     <Fontsize>10.0</Fontsize> 
     <FontStyle>Normal</FontStyle> 
     <Caption /> 
     <_x0032_DBarcode_Margin>1</_x0032_DBarcode_Margin> 
     <_x0032_DBarcode_ModSize>5</_x0032_DBarcode_ModSize> 
     <MOL_WIDTH>200</MOL_WIDTH> 
     <MOL_HEIGHT>200</MOL_HEIGHT> 
     <_x0020_MOL_MARGIN>15</_x0020_MOL_MARGIN> 
     <MOL_BONDLINEWIDTH>2</MOL_BONDLINEWIDTH> 
     <MOL_BONDSPACEING>5</MOL_BONDSPACEING> 
     <MOL_FONTSIZE>15</MOL_FONTSIZE> 
     <xpos_Inches>150</xpos_Inches> 
     <ypos_Inches>600</ypos_Inches> 
     <width_Inches>110</width_Inches> 
     <height_Inches>510</height_Inches> 
     <LogoImageName>110</LogoImageName> 
     <ypos_int>110</ypos_int> 
     <xpos_int>510</xpos_int> 
    </LabelData> 
    .... 
    .... 
</NewDataSet> 

我想將LabelDetails轉換爲XML並創建一個包含各行的Temp Table:

uid commonname id name column type  xpos ypox ... 
1234 OrderType1 1  col col  TEXT  5  5  ... 
1234 OrderType1 2  mol mol  MOLIMAGE 1  1  ... 
6789 OrderType2 1  col col  TEXT  5  5  ... 

我不認爲所有的XML表格都相同的行...假設不

我已經看了對方/從XML的問題和他們都不適合和我有點損失的下一步去哪裏...

最終,我期待轉換爲/從XML數據與目標是使用此作爲「停止差距」之間的我們的「系統」存儲這些數據的新方式以及一種新的方式。

我在哪裏可以開始創建2個存儲過程:FromXMLtoTable和FromTableToXML

回答

2

這將讓你開始。我不得不做類似的事情。這可能不是確切的答案,但有一些代碼可用於將XML數據提取到SQL表中。

--Set tempXML for testing 
CREATE TABLE #tempXML(id INT IDENTITY(1,1) PRIMARY KEY, xmlData XML) 
INSERT INTO #tempXML(xmlData) 
VALUES('<NewDataSet> 
    <LabelData> 
     <Name>mol</Name> 
     <Column>mol</Column> 
     <Type>MOLIMAGE</Type> 
     <xpos>510</xpos> 
     <ypos>110</ypos> 
     <width>auto</width> 
     <height>auto</height> 
     <Font>Arial</Font> 
     <Fontsize>10.0</Fontsize> 
     <FontStyle>Normal</FontStyle> 
     <Caption /> 
     <_x0032_DBarcode_Margin>1</_x0032_DBarcode_Margin> 
     <_x0032_DBarcode_ModSize>5</_x0032_DBarcode_ModSize> 
     <MOL_WIDTH>200</MOL_WIDTH> 
     <MOL_HEIGHT>200</MOL_HEIGHT> 
     <_x0020_MOL_MARGIN>15</_x0020_MOL_MARGIN> 
     <MOL_BONDLINEWIDTH>2</MOL_BONDLINEWIDTH> 
     <MOL_BONDSPACEING>5</MOL_BONDSPACEING> 
     <MOL_FONTSIZE>15</MOL_FONTSIZE> 
     <xpos_Inches>150</xpos_Inches> 
     <ypos_Inches>600</ypos_Inches> 
     <width_Inches>110</width_Inches> 
     <height_Inches>510</height_Inches> 
     <LogoImageName>110</LogoImageName> 
     <ypos_int>110</ypos_int> 
     <xpos_int>510</xpos_int> 
    </LabelData> 
</NewDataSet>') 

    SELECT r.value('Name[1]', 'nvarchar(100)') AS Field1 
      , r.value('Column[1]', 'nvarchar(100)') AS Field2 
      , r.value('Type[1]', 'nvarchar(100)') AS Field3 
      --etc... 
    FROM #tempXML 
     CROSS APPLY xmlData.nodes('/NewDataSet/LabelData') AS x(r) 
------------------------------------------------------------------------ 

    DECLARE @loopCount   INT 
    DECLARE @recordID   INT 
    DECLARE @columnName   NVARCHAR(128) 
    DECLARE @dataType   NVARCHAR(10) 
    DECLARE @strSQL    NVARCHAR(MAX) 
    DECLARE @fieldValue   NVARCHAR(MAX) 

    --This table will store your Columns from your new table of xml parsed data 
    CREATE TABLE #TableFields 
    (
     id int not null identity, 
     COLUMN_NAME NVARCHAR(100), 
     DATA_TYPE NVARCHAR(10) 
    ) 

    --Insert column names from xml parsed data to TableFields temp table 
    INSERT INTO #TableFields (COLUMN_NAME, DATA_TYPE) 
    SELECT COLUMN_NAME, DATA_TYPE 
    FROM Information_Schema.Columns 
    WHERE Table_Name = 'Insert Table Here' 
      AND COLUMN_NAME <> 'ID' 

    --Create your xml parsed table(or use a physical one) 
    CREATE TABLE #temptable 
    (
     id INT IDENTITY(1,1), 
     field1 VARCHAR(100), 
     field2 VARCHAR(100), 
     field3 VARCHAR(100) 
     --etc... 
    ) 

    --Insert the parsed xml from #tempXML test table to #tempTable 
    INSERT INTO #temptable(fieldName, fieldValue, xmlID) 
    SELECT r.value('Name[1]', 'nvarchar(100)') AS Field1 
      , r.value('Column[1]', 'nvarchar(100)') AS Field2 
      , r.value('Type[1]', 'nvarchar(100)') AS Field3 
      --etc... 
    FROM #tempXML 
     CROSS APPLY xmlData.nodes('/NewDataSet/LabelData') AS x(r) 

    --Set a loopCount for while loop 
    SET @loopCount = 1 

    --Use the while loop to check if we have any fields left to go through 
     while (exists(SELECT id FROM #TableFields WHERE id = @loopCount)) 
      BEGIN 

       --Get current record in temp table 
       SELECT @columnName  = t.COLUMN_NAME, 
         @dataType  = t.DATA_TYPE, 
         @fieldValue  = v.fieldValue, 
         @recordID  = v.xmlID 
       FROM #TableFields t 
        JOIN #temptable v ON 
         t.id = v.id AND 
         t.COLUMN_NAME = v.fieldName 
       WHERE t.id = @loopCount 
       -----------------------------------------------------------   

       SET @strSQL = 'UPDATE [insert your table here] SET ' + @columnName + ' = ''' + CONVERT(NVARCHAR(MAX), @fieldValue) + ''' FROM [insert your table here] WHERE ID = ' + CONVERT(NVARCHAR(MAX), @recordID) 
       EXEC sp_executesql @strSQL, N'@columnName varchar(128)', @columnName = @columnName 


       DELETE FROM #TableFields WHERE id = @loopCount 

       SET @loopCount = @loopCount + 1 
      END 


    DROP TABLE #TableFields 
    DROP TABLE #temptable 
    DROP TABLE #tempXML 
+0

這可能工作,但是很複雜...如果有可能避免循環......有很多關於如何閱讀未知XML使用'local-name()'和'PIVOT'或*分組聚合*與動態創建的語句... – Shnugo

0

編寫XML

爲了讓您的XML你描述它的方式很簡單:

SELECT * FROM AnySource FOR XML RAW(N'LabelData'),ELEMENTS,ROOT(N'NewDataSet') 

這適用於任何表,視圖或表值函數...

閱讀XML

讀取未知XML很容易,如果您的目標是實體鍵值三元組:

DECLARE @xml XML= 
N'<NewDataSet> 
    <LabelData> 
     <Name>mol</Name> 
     <Column>mol</Column> 
     <Type>MOLIMAGE</Type> 
     <!--More elements--> 
     <TEST1>Only existing in 1</TEST1> 
    </LabelData> 
    <LabelData> 
     <Name>2nd name</Name> 
     <Column>2nd col</Column> 
     <Type>2nd type</Type> 
     <!--More elements--> 
     <TEST2>Only existing in 2</TEST2> 
    </LabelData> 
</NewDataSet>'; 

WITH NewDataSet aS 
(
    SELECT ROW_NUMBER() OVER(ORDER BY (SELECT NULL)) AS OrdPosition 
      ,ld.query('./*') AS LabelDataElements 
    FROM @xml.nodes(N'/NewDataSet/LabelData') AS A(ld) 
) 
SELECT ds.OrdPosition 
     ,AllNodes.value(N'local-name(.)',N'nvarchar(max)') AS ElementName 
     ,AllNodes.value(N'(./text())[1]',N'nvarchar(max)') AS ElementValue 
FROM NewDataSet AS ds 
CROSS APPLY ds.LabelDataElements.nodes(N'*') AS A(AllNodes); 

導致

+-------------+-------------+--------------------+ 
| OrdPosition | ElementName | ElementValue  | 
+-------------+-------------+--------------------+ 
| 1   | Name  | mol    | 
+-------------+-------------+--------------------+ 
| 1   | Column  | mol    | 
+-------------+-------------+--------------------+ 
| 1   | Type  | MOLIMAGE   | 
+-------------+-------------+--------------------+ 
| 1   | TEST1  | Only existing in 1 | 
+-------------+-------------+--------------------+ 
| 2   | Name  | 2nd name   | 
+-------------+-------------+--------------------+ 
| 2   | Column  | 2nd col   | 
+-------------+-------------+--------------------+ 
| 2   | Type  | 2nd type   | 
+-------------+-------------+--------------------+ 
| 2   | TEST2  | Only existing in 2 | 
+-------------+-------------+--------------------+ 

但隨着local-name()寫入到表以此爲列標題是更加棘手。有兩種情況:

  • 您事先知道所有可能的列名,即使不是每個XML名都必須包含所有可能的列名。
  • 您的XML包含各種不同的元素,並且您不提前知道這些名稱。

知道列名

一個大優勢:您 - 可能 - 知道數據類型,你可以適當地讀/施放的所有值!

列命名可以PIVOT分組集合,有噸的例子找到...

使用SELECT ... INTO SomeStagingTable FROM ...完成在飛行中創建一個表。

未知列名

在這種情況下,我會跟實體鍵值 tupels列表堅持。您可以使用動態創建的SQL來實現動態定義的PIVOT方法(周圍有很多示例!),但這在以後的查詢中很難使用。在物理表中沒有多少意義,你不知道結構...

相關問題