【问题标题】:How to store results of a Dynamic Query in a temp table without creating a table?如何在不创建表的情况下将动态查询的结果存储在临时表中?
【发布时间】:2021-07-22 12:46:06
【问题描述】:

我们正在编写一个存储过程,负责获取存储过程名称并返回包含存储过程列及其数据类型的结果。 但是,我们在执行动态查询以返回存储过程的结果时遇到了问题,但我们无法将其存储在临时表中!

您可以在下面看到我们的查询:

  DECLARE @ProcName VARCHAR(100)='spGetOraganizationsList',
  @ParamName VARCHAR(100),@DataType VARCHAR(20),
  @Query NVARCHAR(MAX)='EXEC '+'spGetOraganizationsList '

  SELECT  PARAMETER_NAME,DATA_TYPE 
  INTO #Tmp
  FROM  information_schema.PARAMETERS
  WHERE SPECIFIC_NAME=@ProcName

  DECLARE ParamCursor CURSOR 
  FOR SELECT * FROM #Tmp
  OPEN ParamCursor
  FETCH NEXT FROM ParamCursor
  INTO @ParamName,@DataType

  WHILE @@FETCH_STATUS = 0 
  BEGIN
  SET @Query=@Query+@ParamName+'=Null,'
  FETCH NEXT FROM ParamCursor INTO @ParamName,@DataType
  END
  CLOSE ParamCursor
  DEALLOCATE ParamCursor
  DROP TABLE #Tmp
  
  EXEC sp_executesql @Query

问题是我无法将它的结果存储在临时表中, 而OPENROWSET 不接受变量。

【问题讨论】:

  • 无法将结果存储到临时表中是什么意思?你有错误吗?
  • 我的意思是 EXEC sp_executesql @Query 的结果......你不能通过“查询”方法将它的结果存储到临时表中。
  • 您能否发布脚本执行后遇到的确切错误。
  • 你能编辑你的问题,指出失败的行,以及确切的错误信息
  • 好的,现在您终于描述了您的问题。也许您应该尝试使用它:docs.microsoft.com/en-us/sql/relational-databases/…

标签: sql sql-server


【解决方案1】:

我认为它来自 sql 概念,它不信任存储过程的结果,因此我们无法通过“在查询表中制作”方法对其进行选择或将其存储在表中。 除非您创建一个表并定义它的列和对您的 sql 信任,并且您将它的结果插入到该表中,例如采取以下情况

Create table test (name varchar(10),family varchar(20))


Insert into test
Exec sp-testResult

现在,如果您为表定义错误的列,您将收到查询运行时错误。实际上 sql 不会预测 sp 的结果,而是让您定义存储过程的结果。

【讨论】:

    【解决方案2】:

    您当然可以将存储过程的结果插入到 TEMP 表中:

    CREATE PROCEDURE PurgeMe
    AS
    SELECT convert(int, 1) AS DaData
    UNION
    SELECT convert(int, 2)
    GO
    
    CREATE TABLE #Doodles  (AnInteger int)
    
    INSERT #Doodles EXECUTE PurgeMe
    
    SELECT * FROM #Doodles
    

    但是,关于 TEMP 表的范围存在疑问。您可能会发现,在您的调用例程中,您将无法看到在您的例程中创建的 TEMP 表。

    SCOPE问题的解决方法如下:

    1. 创建一个最小的 TEMP 表(比如,只有一列)
    2. 在例程中对 TEMP 表使用 ALTER TABLE 以使其架构匹配 您的需求(这可能很棘手,但可以做到)
    3. 将数据放入TEMP表中
    4. 从您的例程返回 - 调用例程现在可以访问临时 表

    如果对此感兴趣,我可以使用存储过程来做更长的帖子来执行上述操作。它是为了促进动态 SQL 而编写的

    【讨论】:

    • 谢谢'Wayane'的回答,但是临时表范围无关紧要,实际上我们想要存储过程的名称并将其结果存储到临时表中而不创建表,你可以看看我上面写的查询,因此你的答案不适合这种情况
    • 在您最初的帖子中,您写道“我们不能将它存储在临时表中”,但我认为您的意思不是“不可能”。在您对我的评论中,您写道“将其结果存储到临时表中而不创建表”。当然,为了将数据存储到表中,表必须存在,无论您使用将创建表的“SELECT INTO #TempTable”,还是对已经存在的表使用“INSERT #TempTable SELECT ...”。也许您可以更详细地解释这些短语的含义。
    【解决方案3】:

    在存储过程中根据需要编写选择查询。无需创建临时表即可获得结果。

    【讨论】:

      【解决方案4】:

      使用全局临时表和动态OPENROWSET

        DROP TABLE ##Tmp;
        GO
      
        DECLARE @ProcName VARCHAR(100)='spGetOraganizationsList',
        @ParamName VARCHAR(100), @DataType VARCHAR(20),
        -- Mind to specify database and schema of the SP
        @Query NVARCHAR(MAX)=' EXEC [mydb].[dbo].spGetOraganizationsList ';
        SELECT  PARAMETER_NAME,DATA_TYPE 
        INTO #Tmp
        FROM  information_schema.PARAMETERS
        WHERE SPECIFIC_NAME=@ProcName;
      
        -- Build SP exec
      
        DECLARE ParamCursor CURSOR 
        FOR SELECT * FROM #Tmp
        OPEN ParamCursor
        FETCH NEXT FROM ParamCursor
        INTO @ParamName,@DataType
      
        WHILE @@FETCH_STATUS = 0 
        BEGIN
           SET @Query=@Query+@ParamName+'=Null,'
           FETCH NEXT FROM ParamCursor INTO @ParamName,@DataType
        END
        CLOSE ParamCursor
        DEALLOCATE ParamCursor
        SET @Query = left(@Query, len(@Query) - 1);
      
        -- Build ad hoc distributed query which creates ##Tmp from SP exec.
      
        SET @Query = 'SELECT * INTO ##Tmp FROM OPENROWSET(''SQLNCLI'', ''Server=localhost;Trusted_Connection=yes;'',''' + @Query + ''')';
      
        EXEC (@Query);
      
        -- Created by dynamic sql `##Tmp` is availabe in the current context. 
        SELECT *
        FROM ##Tmp;
      

      不要忘记先启用临时分布式查询。

      sp_configure 'Show Advanced Options', 1
      GO
      RECONFIGURE
      GO
      sp_configure 'Ad Hoc Distributed Queries', 1
      GO
      RECONFIGURE
      GO
      

      编辑

      我的答案只解决了一个问题,将动态 proc 调用的结果存储在临时表中。还有更多的问题。

      首先,如果@p 的类型是用户定义的表类型,@p=null 将不会编译。你需要declare @t myType; exec mySp ... ,@p=@t ...

      接下来是您评论的“无法检索 sp 的元数据,因为包含动态查询”错误。看起来你需要一个应用程序,SqlClr 或独立的,它能够读取和解析 procs 返回的数据集。

      最后,如果 SP 包含条件 sql,它可以根据参数值返回不同模式的结果集,那么所有这些努力的结果仍然值得怀疑。

      【讨论】:

      • 包含动态查询的存储过程呢?当您尝试为此类存储过程检索元数据时,您将收到一条错误消息“无法检索 sp 的元数据,因为包含动态查询”您在使用“sp_describe_first_result_set”时也会收到相同的错误
      • 感谢您对这个话题感兴趣,但是我收到了您的一个问题,您认为可以编写一个接受 sp 名称并返回列名及其数据类型的存储过程吗?我认为可能只是存储过程不包含动态查询。
      • @Abolfazl 是的,仅限于没有动态 sql 且没有从临时表中选择结果集的 SP,这应该是可能的。排除用户自定义表类型的参数,上面的代码做到了。 information_schema.PARAMETERS 视图还包含声明该类型参数所需的变量的所有信息。
      • 我已经写了一个sp,通过sp名称返回sp的结果,但是我想找到一个带有临时表和动态查询的sps解决方案,无论如何感谢您分享您的知识。
      【解决方案5】:

      在 C# 中,您可以使用 SqlDataReader 或 DataTable 从存储过程中获取结果,而无需事先了解架构。如果您想将该数据写入临时表,我认为您可以从 C# 中执行此操作(尽管我从未尝试过这样做)。

      【讨论】:

        猜你喜欢
        • 2014-10-26
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2016-06-12
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多