【问题标题】:How to return temporary table from stored procedure如何从存储过程中返回临时表
【发布时间】:2010-11-29 10:38:09
【问题描述】:
CREATE PROCEDURE [test].[proc]
@ConfiguredContentId int,
@NumberOfGames int
AS
BEGIN
 SET NOCOUNT ON
 RETURN 
 @WunNumbers TABLE (WinNumb int)

    INSERT INTO @WunNumbers (WinNumb)
 SELECT TOP (@NumberOfGames) WinningNumber
 FROM [Game].[Game] g
 JOIN [Game].[RouletteResult] AS rr ON g.[Id] = rr.[gameId]
 WHERE g.[ConfiguredContentId] = @ConfiguredContentId
 ORDER BY g.[Stoptime] DESC

 SELECT WinNumb, COUNT (WinNumb) AS "Count"
 FROM @WunNumbers wn
 GROUP BY wn.[WinNumb]
END
GO

此存储过程从第一个 select 语句返回值,但我希望从第二个 select 语句返回值。表@WunNumbers 是一个临时表。

有什么想法吗???

【问题讨论】:

  • 请重新格式化您的 sql 代码。
  • 该代码不是有效的 SQL。可能是,如果“RETURN @WinNumbers”是“DECLARE @WinNumbers”,那么它的其余部分看起来正确返回最终结果集
  • 我现在看到了,我发布了错误的代码。有“DECLARE @WinNumbers”,但它仍然不起作用。

标签: sql-server stored-procedures temp-tables


【解决方案1】:

您使用的是什么版本的 SQL Server?在 SQL Server 2008 中,您可以使用 Table Parameters and Table Types

另一种方法是从用户定义的函数中返回一个表变量,但我不是这种方法的忠实粉丝。

你可以找到一个例子here

【讨论】:

    【解决方案2】:

    看看这段代码,

    CREATE PROCEDURE Test
    
    AS
        DECLARE @tab table (no int, name varchar(30))
    
        insert @tab  select eno,ename from emp  
    
        select * from @tab
    RETURN
    

    【讨论】:

    • 如何将表变量返回/输出给调用者?它当前返回一个结果集。
    • 它返回select语句的结果(实际问题),在这种情况下,恰好是本地表变量@tab的内容。
    • 如果我这样做 EXECUTE Test 我如何访问 @tab ?
    • 我正在做类似的事情;当我在管理工作室中运行它时,我看到了我的结果集,但是当我使用 ADO.net 运行它时,SqlReader 得到一个空的结果集。
    【解决方案3】:

    过程的返回类型是int。

    您还可以返回结果集(就像您的代码当前所做的那样)(好吧,您也可以发送消息,它们是字符串)

    这些是您唯一可以做出的“回报”。虽然您可以将表值参数添加到过程中(请参阅 BOL),但它们只是输入。

    编辑:

    (或者正如另一张海报提到的,您也可以使用表值函数,而不是过程)

    【讨论】:

      【解决方案4】:

      可以在调用者中创建一个临时表,然后从被调用的 SP 中填充。

        create table #GetValuesOutputTable(
           ...   
        );
      
        exec GetValues; -- populates #GetValuesOutputTable
      
        select * from #GetValuesOutputTable;
      

      与“insert exec”相比,这种方法的一些优点是它可以嵌套,并且可以用作输入或输出。

      一些缺点是“参数”不是公共的,表的创建存在于每个调用者中,并且表的名称可能与其他临时对象发生冲突。当临时表名称与 SP 名称紧密匹配并遵循某些约定时,它会有所帮助。

      再进一步,对于仅输出临时表,被调用的 SP 可以同时支持 insert-exec 方法和临时表方法。这对于链接 SP 并没有太大帮助,因为表仍然需要在调用者中定义,但可以帮助简化从 cmd 行或外部调用时的测试。

        -- The "called" SP
        declare
            @returnAsSelect bit = 0;
      
        if object_id('tempdb..#GetValuesOutputTable') is null
        begin
            set @returnAsSelect = 1;
            create table #GetValuesOutputTable(
               ...   
            );
        end
      
        -- populate the table
      
        if @returnAsSelect = 1
            select * from #GetValuesOutputTable;
      

      【讨论】:

        【解决方案5】:

        可以。

        在您的存储过程中,您填写表@tbRetour

        在存储过程的最后,你写:

        SELECT * FROM @tbRetour 
        

        要执行存储过程,请编写:

        USE [...]
        GO
        
        DECLARE @return_value int
        
        EXEC @return_value = [dbo].[getEnregistrementWithDetails]
        @id_enregistrement_entete = '(guid)'
        
        GO
        

        【讨论】:

          【解决方案6】:

          首先创建一个真实的永久表作为模板,该模板具有返回的临时表所需的布局,使用将其标识为模板并将其符号链接到 SP 的命名约定,例如 tmp_SPName_Output。此表永远不会包含任何数据。

          在 SP 中,使用 INSERT 将数据加载到遵循相同命名约定的临时表中,例如#SPName_Output 假定存在。您可以测试它是否存在,如果不存在则返回错误。

          在调用 sp 之前,使用这个简单的选择来创建临时表:

          SELECT TOP(0) * INTO #SPName_Output FROM tmp_SPName_Output;
          EXEC SPName;
          -- Now process records in #SPName_Output;
          

          这具有以下明显优势:

          • 临时表是当前会话的本地表,与 ## 不同,因此不会与从 不同的会话。它也会在超出范围时自动删除。
          • 模板表与 SP 一起维护,因此如果更改 对输出(例如添加的新列)然后预先存在 SP 的调用者不会中断。调用者无需更改。
          • 您可以定义任意数量的具有不同命名的输出表 一个 SP 并将它们全部填满。您还可以定义替代输出 使用不同的命名并让 SP 检查温度的存在 查看需要填写的表格。
          • 类似地,如果进行了重大更改但您想保持倒退 兼容性,你可以有一个新的模板表和命​​名为以后 版本,但仍然通过检查哪个温度来支持早期版本 调用者创建的表。

          【讨论】:

            猜你喜欢
            • 2016-10-06
            • 1970-01-01
            • 2021-09-02
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多