【问题标题】:Dynamic SQL Result INTO Temporary Table动态 SQL 结果 INTO 临时表
【发布时间】:2015-01-03 06:18:01
【问题描述】:

我需要将动态sql结果存入临时表#Temp

动态 SQL 查询结果来自 pivot 结果,因此列数不同(不固定)。

SET @Sql = N'SELECT ' + @Cols + ' FROM 
        (
           SELECT ResourceKey, ResourceValue 
           FROM LocaleStringResources where StateId ='
+ LTRIM(RTRIM(@StateID)) + ' AND FormId =' + LTRIM(RTRIM(@FormID))
+ ' AND CultureCode =''' + LTRIM(RTRIM(@CultureCode)) + '''
         ) x
        pivot 
        (
            max(ResourceValue)
            for ResourceKey IN (' + @Cols + ')
        ) p ;'

     --@Cols => Column Names which varies in number

现在我必须将动态 sql 结果插入到 #Temp 表中,并将此 #Temp 表与另一个现有表一起使用来执行连接或其他操作。

#Temp 表应该存在那里以执行与其他现有表的操作)

如何将动态 SQL 查询结果插入到临时表中?

谢谢

【问题讨论】:

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


【解决方案1】:

你能试试下面的查询吗?

SET @Sql = N'SELECT ' + @Cols + ' 
    into ##TempTable
    FROM 
    (
       SELECT ResourceKey, ResourceValue 
       FROM LocaleStringResources where StateId ='
       + LTRIM(RTRIM(@StateID)) + ' AND FormId =' + LTRIM(RTRIM(@FormID))
       + ' AND CultureCode =''' + LTRIM(RTRIM(@CultureCode)) + '''
     ) x
    pivot 
    (
        max(ResourceValue)
        for ResourceKey IN (' + @Cols + ')
    ) p ;'

然后您可以使用##TempTable 进行进一步操作。

但是,不要忘记在查询末尾删除##TempTable,因为如果再次运行查询,它会报错,因为它是Global Temporary Table

【讨论】:

  • 当同一查询在另一个会话中运行时,这将失败
【解决方案2】:

正如 (https://social.msdn.microsoft.com/Forums/sqlserver/en-US/144f0812-b3a2-4197-91bc-f1515e7de4b9/not-able-to-create-hash-table-inside-stored-proc-through-execute-spexecutesql-strquery?forum=sqldatabaseengine) 中的回答,

需要提前创建#Temp表:

CREATE TABLE #Temp(columns definition);

如果您事先对动态列列表一无所知,这似乎是不可能完成的任务。但是,您很可能确实知道一些事情。

您确实知道动态列的类型,因为它们来自PIVOT。您很可能知道动态列的最大可能数量。即使您不这样做,SQL Server 每个(非宽)表也有 1024 列的限制,并且每行有 8060 字节的限制 (http://msdn.microsoft.com/en-us/library/ms143432.aspx)。因此,您可以提前创建一个具有最大可能列数的#Temp 表,并仅使用其中的一些(使您的所有列都可以为空)。

所以,CREATE TABLE 将如下所示(而不是 int 使用您的类型):

CREATE TABLE #Temp(c1 int NULL, c2 int NULL, c3 int NULL, ..., c1024 int NULL);

是的,#Temp 中的列名将与 @Cols 中的不同。您的处理应该没问题。

您的@Cols 变量中有一个列列表。您以某种方式在一些外部代码中制作了此列列表,因此当生成@Cols 时,您知道有多少列。此时,您应该能够生成与#Temp 的定义匹配的第二个列列表。比如:

@TempCols = N'c1, c2, c3, c4, c5';

@TempCols 中的列数应与@Cols 中的列数相同。那么您的动态 SQL 将如下所示(我在您的代码前面添加了INSERT INTO #Temp (@TempCols)):

SET @Sql = N'INSERT INTO #Temp (' + @TempCols + N') SELECT ' + @Cols + N' FROM 
        (
           SELECT ResourceKey, ResourceValue 
           FROM LocaleStringResources where StateId ='
+ LTRIM(RTRIM(@StateID)) + ' AND FormId =' + LTRIM(RTRIM(@FormID))
+ ' AND CultureCode =''' + LTRIM(RTRIM(@CultureCode)) + '''
         ) x
        pivot 
        (
            max(ResourceValue)
            for ResourceKey IN (' + @Cols + ')
        ) p ;'

然后你执行你的动态 SQL:

EXEC (@Sql) OR sp_executesql @Sql

然后使用#Temp表和临时列名c1, c2, c3, ...进行其他处理

MSDNsays:

在存储过程中创建的本地临时表被删除 存储过程完成时自动执行。

您也可以明确地DROP #Temp 表,如下所示:

IF OBJECT_ID('tempdb..#Temp') IS NOT NULL
DROP TABLE #Temp'

所有这些 T-SQL 代码(CREATE TABLEEXEC、...您的自定义处理...、DROP TABLE)自然会在存储过程中。

【讨论】:

  • 列列表是动态生成的怎么办期望CREATE TABLE #Temp(columns definition) in advance
  • @NoDisplayName,与@Cols变量中用于动态生成列列表的过程/函数/方法相同,可用于生成非常相似的列列表及其语法中的类型这适用于CREATE TABLE 语句。如果可以动态生成@Cols = 'Column1, Column2, Column3, ...',那么也可以动态生成@ColsWithTypes = 'Column1 int, Column2 nvarchar(nn), Column3 nvarchar(nn), ...',不是吗?
  • @NoDisplayName,我错了。我以为我可以EXECCREATE TABLE #Temp,但现在我意识到,在EXEC 内部创建的这个临时表不会在EXEC 外部看到。
  • @NoDisplayName,我改变了答案。现在我建议 CREATE TABLE #Temp 提前尽可能多的列,以后只使用其中的一些。
  • @SarathAvanavu,你是对的。这就是我编辑答案的原因。我不再建议使用动态 SQL 创建 #Temp 表。我建议使用普通的“静态”CREATE TABLE 语句创建一个#Temp 表,并在此类#Temp 表中静态创建最大可能的列,其中只有一些将使用动态 SQL 的EXEC 填充实际数据。
【解决方案3】:

创建临时表的替代方法是使用子查询

select t1.name,t1.lastname from(select * from table)t1.

其中 "select * from table" 是您的 dyanmic query。这将返回结果,您可以将其用作temp table t1,如示例中所示。

【讨论】:

    【解决方案4】:
    IF OBJECT_ID('tempdb..##TmepTable') IS NOT NULL DROP TABLE ##TmepTable
         CREATE TABLE ##TmepTable (TmpCol CHAR(1))
    DECLARE @SQL NVARCHAR(max) =' IF OBJECT_ID(''tempdb..##TmepTable'') IS NOT 
    NULL DROP TABLE ##TmepTable 
    SELECT * INTO ##TmepTable  from [MyTableName]'
        EXEC sp_executesql @SQL
    SELECT  Alias.* FROM ##TmepTable as Alias
    
    IF OBJECT_ID('tempdb..##TmepTable') IS NOT NULL DROP TABLE ##TmepTable 
    

    【讨论】:

      【解决方案5】:

      这里是您问题的分步解决方案。

      1. 检查您的临时表(如果存在)并将其删除。
      IF OBJECT_ID('tempdb..#temp') IS NOT NULL
      DROP TABLE #temp
      
      IF OBJECT_ID('tempdb..##abc') IS NOT NULL
      DROP TABLE ##abc
      
      1. 将您的主要查询结果存储在第一个临时表中(此步骤是为了简化和提高可读性)。
      SELECT * 
      INTO   #temp 
      FROM   (SELECT ResourceKey, ResourceValue 
      FROM LocaleStringResources 
      where StateId ='+ LTRIM(RTRIM(@StateID)) + ' AND FormId =' + LTRIM(RTRIM(@FormID))
      + ' AND CultureCode =' + LTRIM(RTRIM(@CultureCode)) + ') AS S
      


      1. 在下面编写查询以创建您的pivot 并将结果存储在另一个临时表中。
      DECLARE @str NVARCHAR(1000) 
      DECLARE @sql NVARCHAR(1000)      
      SELECT @str = COALESCE(@str+',', '') + ResourceKey FROM   #temp 
      
      SET @sql = N'select * into ##abc from (select ' + @str + ' from (SELECT ResourceKey, ResourceValue FROM #temp) as A 
      Pivot 
      (   
        max(ResourceValue)
        for ResourceKey in (' + @str + ')  
      )as pvt) as B'
      
      1. 执行以下查询以在您的下一个 temp table ##abc 中获取数据透视结果。

      EXECUTE sp_executesql @sql

      1. 现在您可以将##abc 用作您想要的任何地方的表格

      select * from ##abc

      希望这会对您有所帮助。

      【讨论】:

        猜你喜欢
        • 2016-01-22
        • 1970-01-01
        • 2010-10-14
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-02-24
        • 2010-11-21
        • 1970-01-01
        相关资源
        最近更新 更多