Sql server 将文本XML转换为Sql表。。。来回

Sql server 将文本XML转换为Sql表。。。来回,sql-server,xml,data-conversion,Sql Server,Xml,Data Conversion,我有一张桌子: with XMLData as ( SELECT uid, commonname, cast(labeldetails as XML) labelxml FROM [MyLables] ) SELECT uid ,commonname ,labelxml FROM XMLData [x] 为了简洁起见,我把它浓缩了: B8A3DF5E OrderType1 <NewDataSet><LabelData

我有一张桌子:

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表都有相同的行。。。假设你没有

我已经研究了其他的“从XML到/从XML”的问题,它们似乎都不合适,我有点不知道下一步该怎么办

最后,我希望转换XML数据,目的是将其用作旧的系统存储数据方式和新的数据存储方式之间的一种临时方法


从哪里开始创建2个存储过程:FromXMLtoTable和FromTableToXML

这将帮助您开始。我不得不做类似的事情。这可能不是一个确切的答案,但有一些代码可用于将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
编写XML 要以您描述的方式获取XML,很简单:

SELECT * FROM AnySource FOR XML RAW(N'LabelData'),ELEMENTS,ROOT(N'NewDataSet')
这适用于任何表、视图或表值函数

读取XML 如果目标是实体键值元组,则读取未知XML很容易:

但将其写入以本地名称作为列标题的表更为棘手。有两种情况:

您事先不知道所有可能的列名,即使不是每个列名,任何XML都必须包含所有列名。 XML包含各种不同的元素,您事先不知道这些元素的名称。 已知列名 一大优势是:您可能知道数据类型,并且可以适当地读取/转换所有值

列命名可以通过PIVOT或grouped aggregate完成,有大量的示例可供查找

使用选择。。。进入某个阶段,从。。。要动态创建表,请执行以下操作

未知列名
在本例中,我将坚持使用实体键值元组列表。您可能会使用动态创建的SQL来实现动态定义的枢轴方法,例如!,但这在以后的查询中很难使用。在物理表中没有太多意义,因为您不知道其结构…

这可能有效,但非常复杂。。。如果可能的话,避免循环。。。关于如何使用本地名称和透视或使用动态创建的语句进行分组聚合来读取未知XML,有许多示例。。。
--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
SELECT * FROM AnySource FOR XML RAW(N'LabelData'),ELEMENTS,ROOT(N'NewDataSet')
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 |
+-------------+-------------+--------------------+