【问题标题】:How dynamically insert data in respective tables based upon xml in Sql serverSql server中如何根据xml在各个表中动态插入数据
【发布时间】:2015-05-25 05:56:44
【问题描述】:

我在存储过程中有这种类型的输入XML 参数传递,它是从我的.net 应用程序传递的。

现在,我需要在各个表中插入记录:

<root>
<table1>
<patid>123</patid>
<name>gresh</name>
<fname>kumar</name>
</table1>
<table2>
<patid>123</patid>
<Schoolname>12345</Schoolname>
</table2>
<tablen>
<patid>123</patid>
<nfield>12345</nfield>
</tablen>
<root>

假设table1 将在table1 中插入数据,table2table2 中的数据,tablen 中可能存在XML 中的其他表的平均数量。

那么如何在各个表中插入呢?

【问题讨论】:

    标签: sql-server sql-server-2008 tsql sql-server-2008-r2 sql-server-2012


    【解决方案1】:

    您首先需要从XML 获取数据。您的情况非常简单(我假设您只在一个表中插入数据一次,但您可以轻松解决在一个表中多次插入的问题)。所以,下面的语句给了我:

    SELECT T.c.value('local-name(.)','nvarchar(128)') AS tableName
          ,T1.c1.value('local-name(.)','nvarchar(128)') AS columName
          ,T1.c1.value('(./node())[1]','nvarchar(max)') AS value
    FROM @XML.nodes('/root/*') T(c)
    CROSS APPLY T.c.nodes('*') T1(c1)
    

    然后,您需要对每个表的insertion 值进行分组(我使用的是CLR 连接函数(您可以找到它here,但您也可以搜索T-SQL 替代方法):

    ;WITH DataSource(tableName, columName, value)AS
    (
        SELECT T.c.value('local-name(.)','nvarchar(128)')
              ,T1.c1.value('local-name(.)','nvarchar(128)')
              ,T1.c1.value('(./node())[1]','nvarchar(max)')
        FROM @XML.nodes('/root/*') T(c)
        CROSS APPLY T.c.nodes('*') T1(c1)
    )
    SELECT tableName
          ,[dbo].[Concatenate] (columName)
          ,[dbo].[Concatenate] (value)
    FROM DataSource
    GROUP BY tableName
    

    您可以像这样准备上述代码以进一步动态执行:。

    ;WITH DataSource(tableName, columName, value)AS
    (
        SELECT T.c.value('local-name(.)','nvarchar(128)')
              ,T1.c1.value('local-name(.)','nvarchar(128)')
              ,T1.c1.value('(./node())[1]','nvarchar(max)')
        FROM @XML.nodes('/root/*') T(c)
        CROSS APPLY T.c.nodes('*') T1(c1)
    )
    SELECT 'INSERT INTO ' + tableName  + '(' + [dbo].[Concatenate] (columName) + ') VALUES(' + [dbo].[Concatenate] ('''' + value + '''') + ');' 
    FROM DataSource
    GROUP BY tableName
    

    现在,您只需构建一个dynamic T-SQL string 并使用sp_executesql 过程执行它:

    DECLARE @XML XML = N'<root>
    <table1>
    <patid>123</patid>
    <name>gresh</name>
    <fname>kumar</fname>
    </table1>
    <table2>
    <patid>123</patid>
    <Schoolname>12345</Schoolname>
    </table2>
    <tablen>
    <patid>123</patid>
    <nfield>12345</nfield>
    </tablen>
    </root>';
    
    DECLARE @DynamicSQLStatement NVARCHAR(MAX)
    
    ;WITH DataSource(tableName, columName, value)AS
    (
        SELECT T.c.value('local-name(.)','nvarchar(128)')
              ,T1.c1.value('local-name(.)','nvarchar(128)')
              ,T1.c1.value('(./node())[1]','nvarchar(max)')
        FROM @XML.nodes('/root/*') T(c)
        CROSS APPLY T.c.nodes('*') T1(c1)
    )
    SELECT @DynamicSQLStatement =
    (
        SELECT CHAR(10) + 'INSERT INTO ' + tableName  + '(' + [dbo].[Concatenate] (columName) + ') VALUES(' + [dbo].[Concatenate] ('''' + value + '''') + ');' 
        FROM DataSource
        GROUP BY tableName
        FOR XML PATH, TYPE
    ).value('.', 'NVARCHAR(MAX)')
    
    PRINT @DynamicSQLStatement
    
    EXEC sp_executesql @DynamicSQLStatement
    

    请注意,我假设您的 XML 结构在数据库上下文中有效 - 表存在,列存在,并且插入到列中的值是正确的。

    如果需要,您可以添加更多检查。

    【讨论】:

    • 感谢 gotqn,当我在上面执行时,我收到此错误找不到列“dbo”或用户定义的函数或聚合“dbo.Concatenate”,或者名称不明确。我也用过conat函数,但无法解决。
    • 为了使用[dbo].[Concatenate]函数,你需要先阅读下面的文章msdn.microsoft.com/en-us/library/ff878119.aspx——在这里你可以找到你需要的一切(信息和源代码)来创建这个函数。如果您不想使用 CLR 函数,可以在此处使用此答案对结果进行分组 - stackoverflow.com/q/273238/1080354
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2023-03-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-09-29
    • 1970-01-01
    相关资源
    最近更新 更多