【问题标题】:How can I use a Table-Valued Parameter to insert multiple rows and then return their IDs?如何使用表值参数插入多行然后返回它们的 ID?
【发布时间】:2011-11-05 19:26:03
【问题描述】:

在我的应用程序中,我有大量 (100+) 行需要插入到数据库中。一旦他们被插入到数据库中,我需要插入他们的孩子,这些孩子有一个外键引用回孩子。

我想知道是否有一种方法可以编写一个存储过程来插入所有这些行并将它们的 ID 返回给我的应用程序?

【问题讨论】:

  • 这有一种糟糕的计划的味道。为什么这样做,你认为它会更快?只需要一个一个地做——更少的问题恕我直言stackoverflow.com/questions/312003/…
  • @Hogan - 这实际上是一个非常好的优化。单个数据库调用的性能将比 100 高得多。通过网络进行非常成本很高。
  • @Oded - 他仍然需要为每个孩子打电话;将父母和孩子传递给SP并进行100次调用而不是101次不是更好吗?该计划还将减少网络流量——无需将 ID 传递回逻辑层。
  • @Hogan - 你假设错了。它可能会以 2 个电话告终,而第二个电话同时要求所有孩子。
  • @Oded - 在这种情况下,为什么不在第一次通话中将所有孩子与父母一起传递,然后打 1 个电话而不是 2 个电话?就像我说的,难闻的气味。

标签: sql-server-2008 tsql table-valued-parameters


【解决方案1】:

您已使用 table-value-parameters 标记了您的问题 - 您可以将其中一个传递给存储过程以插入数据库。

您可以将OUTPUT 子句与INSERTED 逻辑表一起使用来获取新的ID 值并从存储过程中返回这些值。

【讨论】:

    【解决方案2】:

    这是一个使用 output 子句的示例,就像 Oded 建议的那样。首先,一些设置代码:

    if exists (select * from tempdb.sys.tables where name like '#tmp%')
        drop table #tmp
    create table #tmp (id int identity, FirstName varchar(50), LastName varchar(50))
    
    if exists (select * from sys.procedures where name = 'TestProcedure')
        drop procedure TestProcedure
    if exists (select * from sys.types where name = 'TestTableType')
        drop type TestTableType
    
    create type TestTableType as table (FirstName varchar(50), LastName varchar(50))
    go
    

    现在我们可以创建存储过程了:

    create procedure dbo.TestProcedure
        @List TestTableType readonly
    as
    insert  #tmp
            (FirstName, LastName)
    output  inserted.*
    select  FirstName
    ,       LastName
    from    @List l
    go
    

    注意output 子句,它告诉SQL Server 将插入的行返回给客户端,包括标识列的值。现在代码都设置好了,我们可以测试一下:

    declare @List TestTableType
    insert @List values ('Rick','Cain'),
        ('Herman', 'Gingrich'),
        ('Newt', 'Paul'),
        ('Ron', 'Perry')
    
    exec  dbo.TestProcedure @List
    
    select * from #tmp
    

    您会看到该过程返回的值与#tmp 中的值完全匹配。

    【讨论】:

      【解决方案3】:

      我会做一些类似于 Andomar 建议的事情,但使用此处描述的“INSERT-EXEC”技术:

      http://www.sommarskog.se/tableparam.html

      在链接中搜索:INSERT-EXEC

      【讨论】:

        【解决方案4】:

        我仍在研究如何执行此操作,但在我看来,如果您想插入父表和子表,可以通过将两个表作为表值参数传入一个 sql 调用来完成。如果您有一些人为的身份(关系),它当前像行号一样链接两个表,但不一定存储在任一 DB 表中,那么当插入父级并获取其身份值时,它可以连接到子表使用唯一关系和孩子的外键可以更新。然后可以插入孩子。

        输出很有趣,但我实际上并不需要输出,它只需要在存储过程中使用,所以我必须做更多的研究来看看输出是否可以被使用,例如输出它到临时表。

        回答我自己的问题,输出的语法是:

        [ OUTPUT <dml_select_list> INTO { @table_variable | output_table } [ ( column_list ) ] ]
        

        所以它可以用来创建一个与孩子连接的临时表。

        【讨论】:

        • 你应该提出一个新问题并自己回答
        猜你喜欢
        • 2013-12-08
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-10-03
        • 2017-09-07
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多