【问题标题】:Stored procedure - return identity as output parameter or scalar存储过程 - 作为输出参数或标量返回标识
【发布时间】:2011-03-09 17:14:32
【问题描述】:

当您将记录插入到具有标识列的表中时,您可以使用 SCOPE_IDENTITY() 来获取该值。在存储过程的上下文中,这是返回标识值的推荐方式:

  1. 作为输出参数SET @RETURN_VALUE = SCOPE_IDENTITY()
  2. 作为标量SELECT SCOPE_IDENTITY()
  3. 另一种方式?

各有优缺点?

【问题讨论】:

    标签: sql-server stored-procedures


    【解决方案1】:

    另一种选择是作为存储过程的返回值(不过我不建议这样做,因为这通常最适合错误值)。

    我已经将它包括在插入单行的情况下,以防存储过程被其他 SQL 过程和无法使用 OUTPUT 参数的前端(我相信 .NET 中的 IBATIS ):

    CREATE PROCEDURE My_Insert
        @col1            VARCHAR(20),
        @new_identity    INT    OUTPUT
    AS
    BEGIN
        SET NOCOUNT ON
    
        INSERT INTO My_Table (col1)
        VALUES (@col1)
    
        SELECT @new_identity = SCOPE_IDENTITY()
    
        SELECT @new_identity AS id
    
        RETURN
    END
    

    当从其他存储过程 IMO 调用时,输出参数在 T-SQL 中更易于使用,但某些编程语言对输出参数的支持较差或不支持,并且可以更好地处理结果集。

    【讨论】:

    • 两种方法的好例子,虽然我不认为我会同时做这两种方法,除非我有充分的理由相信两者都需要,例如,如果我不知道什么语言会使用我的 proc,并且知道它需要支持这两种方法。
    • 是的。我不应该说“通常”。我在需要访问两种形式的输出的环境中使用了这两种方法。我会改写我的答案。
    【解决方案2】:

    这一切都取决于您的客户端数据访问层。许多 ORM 框架依赖于在插入操作期间显式查询 SCOPE_IDENTITY。

    如果您完全控制了数据访问层,那么可以说将 SCOPE_IDENTITY() 作为输出参数返回更好。将返回结果包装在结果集中会增加不必要的元数据开销来描述结果集,并使处理请求结果的代码变得复杂。

    如果您更喜欢结果集返回,那么再次使用 OUTPUT 子句可能会更好:

    INSERT INTO  MyTable (col1, col2, col3)
    OUTPUT INSERTED.id, col1, col2, col3
    VALUES (@col1, @col2, @col3);
    

    通过这种方式,您可以获得 整个 插入的行,包括默认列和计算列,并且您会获得一个结果集,其中包含插入的每一行的一行,这与面向集合的批量插入一起正常工作。

    总的来说,当返回 SCOPE_IDENTITY() 作为结果集时,我看不到一个案例。

    【讨论】:

    • 如果有多个插入,返回多行的好处。也许 gbn 打败了你,但你的更彻底。在我的特殊情况下,我没有使用 ORM 并且(目前)不会一次插入多条记录。
    • @Remus:你说,“总的来说,当返回 SCOPE_IDENTITY() 作为结果集时,我看不到一个案例是一个很好的做法。”。那还能怎么做呢?您是否暗示 SCOPE_IDENTITY() 的整体使用是不好的做法?请问是什么意思?
    • @Fernando68:我是说你应该把它作为输出参数,而不是作为结果集
    • 是的,我同意。我以为这就是你的意思。谢谢
    【解决方案3】:

    我更喜欢将标识值作为输出参数返回。 SP的结果应该表明它是否成功。值 0 表示 SP 成功完成,非零值表示错误。此外,如果您需要进行更改并从 SP 返回一个附加值,您无需进行任何更改,只需添加一个附加输出参数。

    【讨论】:

    • 对于它的价值,相同的推理可以应用于选项 1 或 2,如果您需要添加另一个输出值,您可以在选项 1 下添加一个新参数或添加另一个字段到选项 2 下的选择(或其他选择,如果您的消费者支持它)。我自己更喜欢选项 1,基于一个未经证实的假设,即它需要较少的数据库和/或客户端的“开销”。
    • 我同意 jmgant。 SELECT 一个额外的专栏并不难。我知道您可以将输入参数设为可选(使用默认值);输出参数呢?如果不能,更改SELECT 会更容易,因为除非您需要,否则您可能会忽略额外的列。尽管如此,我认为输出参数是没有结果集开销的“正确”方式。
    【解决方案4】:

    作为记录集或输出参数。后者的开销较小,我倾向于使用它而不是单个列/行记录集。

    如果我希望 >1 行,我会使用 OUTPUT 子句和记录集

    返回值通常用于错误处理。

    【讨论】:

      【解决方案5】:
      SELECT IDENT_CURRENT('databasename.dbo.tablename') AS your identity column;
      

      【讨论】:

      • 请编辑更多信息。纯代码和“试试这个”的答案是discouraged,因为它们不包含可搜索的内容,也没有解释为什么有人应该“试试这个”。
      猜你喜欢
      • 2019-07-12
      • 2021-09-04
      • 1970-01-01
      • 2016-08-31
      • 1970-01-01
      • 2022-01-25
      • 2016-10-30
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多