【问题标题】:SQL Insert Into Temp Table in both If and Else BlocksSQL 在 If 和 Else 块中插入临时表
【发布时间】:2011-05-08 13:06:27
【问题描述】:

我正在尝试根据 SQL 2005 中条件的结果填充临时表。无论哪种方式,临时表都将具有相同的结构,但将根据条件使用不同的查询来填充。下面的简化示例脚本在 ELSEINSERT INTO 的语法检查中失败,错误为:

已经有一个对象名为 数据库中的“#MyTestTable”。

DECLARE @Id int
SET @Id = 1

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

IF (@Id = 2) BEGIN 
    SELECT 'ABC' AS Letters
    INTO #MyTestTable;
END ELSE BEGIN
    SELECT 'XYZ' AS Letters
    INTO #MyTestTable;
END

我可以在IF/ELSE 语句之前创建临时表,然后在条件块中执行INSERT SELECT 语句,但是该表将有很多列,我试图提高效率。那是唯一的选择吗?或者有什么方法可以使这项工作?

谢谢, 马特

【问题讨论】:

    标签: sql sql-server-2005 temp-tables insert-into


    【解决方案1】:

    你可以试试这个代码。

    IF (CONDITION HERE)
           begin
               select * into #MyTempTable from tablename ....
           end
           ELSE
               truncate table #MyTempTable 
               insert into #MyTempTable 
               select * from tablename ....
           end
    

    谢谢!!!

    【讨论】:

      【解决方案2】:

      我试过了:

      SELECT S1.* INTO #MytestTable
      FROM 
      (   SELECT 'ABC' AS Letters WHERE 1 = CASE @Id=2 THEN 1 ELSE 2 END
          UNION
          SELECT 'XYZ' AS Letters WHERE 1 = CASE @Id=1 THEN 1 ELSE 2 END
      ) AS S1
      

      如果稍后您需要向#MyTestTable 添加列,则此解决方案会更好,因为否则您必须在重新运行脚本之前物理删除它,这在测试条件下很烦人。

      【讨论】:

        【解决方案3】:

        如果无法预先创建临时表并且不想将核心逻辑放入动态 SQL 中,我会使用此解决方案。

        IF 1 = 1 -- Replace with actual condition
        BEGIN
            SELECT * INTO #tmp1 FROM dbo.Table1
        END
        ELSE
        BEGIN
            SELECT * INTO #tmp2 FROM dbo.Table2
        END
        
        -- Inserting data into global temp table so sql server can't complain on not recognizing in a context
        DECLARE @Command VARCHAR(MAX)
        IF OBJECT_ID('tempdb..#tmp1') IS NOT NULL
        BEGIN
            SET @Command = 'SELECT * INTO ##tmp FROM #tmp1'
        END
        ELSE
        BEGIN
            SET @Command = 'SELECT * INTO ##tmp FROM #tmp2'
        END
        
        EXECUTE(@Command)
        SELECT * INTO #tmpFinal FROM ##tmp -- Again passing data back to local temp table from global temp table to avoid seeing red mark
        
        IF OBJECT_ID('tempdb..##tmp') IS NOT NULL DROP TABLE ##tmp
        IF OBJECT_ID('tempdb..#tmp1') IS NOT NULL DROP TABLE #tmp1
        IF OBJECT_ID('tempdb..#tmp2') IS NOT NULL DROP TABLE #tmp2
        
        SELECT * FROM #tmpFinal
        
        IF OBJECT_ID('tempdb..#tmpFinal') IS NOT NULL DROP TABLE #tmpFinal
        

        【讨论】:

          【解决方案4】:

          回答晚了 8 年,但我很惊讶没有人想到:

          select * into #MyTempTable from...
          where 1=2
          
          IF -- CONDITION HERE
          insert into #MyTempTable select...
          ELSE
          insert into #MyTempTable select...
          

          简单、快速且有效。不需要动态sql

          【讨论】:

          • 太棒了!多年后对于我们这些寻求帮助的人来说仍然很棒。
          • 确实是一个很好的解决方案,但想补充一点,'Select Top 0 *' 比强加一个条件要好。此外,如果原始表包含标识列,则必须在插入之前将其禁用。
          • "Where 1=2" 执行与前 0 完全相同(它也适用于 mysql),因此客观上并不比强加条件更好。不过,您对 ID col 是正确的。
          【解决方案5】:

          此代码可能对您有所帮助

          --creating temptable using columns of two existing tables
          --you can create your temp table Using other methods
          
          select top 0 VI.*,VU.FullName
          into #mytemptable
          from dbo.Items VI inner join
               dbo.Users as VU 
               on VU.Id=VI.Id
          
          --insert your data base on your condition
          if(i<2) --First Condition
          begin
          INSERT INTO #mytemptable
          SELECT VI.*,VU.FullName 
          from dbo.Items VI inner join
               dbo.Users as VU 
               on VU.Id=VI.Id
          end
          Else if(2<i) --Second Condition
          begin
          INSERT INTO #mytemptable
          SELECT VI.*,VU.FullName 
          from dbo.Items VI inner join
               dbo.Users as VU 
               on VU.Id=VI.Id
          end
          
          select * from #mytemptable --show result
          
          drop table #mytemptable --drop table if its needed
          

          此代码适用于 sql server 2014 我不知道它是否适用于 sql 2005

          【讨论】:

            【解决方案6】:

            这是一个老问题,但对于其他来到这里的人来说:

            用户 Philip Kelley 给出的动态 SQL 答案不适用于本地临时表 (#Mytemp)。您可以做的是创建动态 SQL 以将其插入到全局临时表 (##MyTemp) 中,以后可以删除该表。

            DECLARE @Command  varchar(500)
            
            DECLARE @Id int 
            SET @Id = 2
            
            IF OBJECT_ID('tempdb..#MyTestTable') IS NOT NULL DROP TABLE ##MyTestTable 
            
            IF (@Id = 2) BEGIN  
                SET @Command = 'SELECT ''ABC'' AS Letters INTO ##MyTestTable'
            END ELSE BEGIN 
                SET @Command = 'SELECT ''XYZ'' AS Letters INTO ##MyTestTable'
            END 
            
            EXECUTE (@Command)
            
            select * from ##MyTestTable
            
            DROP ##MyTestTable
            

            【讨论】:

              【解决方案7】:

              您遇到的问题不是您正在填充临时表,而是您正在尝试创建该表。 SQL 解析您的脚本并发现您正试图在两个不同的位置创建它,因此会引发错误。意识到“执行路径”不可能同时命中两个 create 语句是不够聪明的。使用动态 SQL 将不起作用;我试过了

              DECLARE @Command  varchar(500)
              
              DECLARE @Id int 
              SET @Id = 2
              
              IF OBJECT_ID('tempdb..#MyTestTable') IS NOT NULL DROP TABLE #MyTestTable 
              
              IF (@Id = 2) BEGIN  
                  SET @Command = 'SELECT ''ABC'' AS Letters INTO #MyTestTable'
              END ELSE BEGIN 
                  SET @Command = 'SELECT ''XYZ'' AS Letters INTO #MyTestTable'
              END 
              
              EXECUTE (@Command)
              
              select * from #MyTestTable
              

              但临时表只持续与动态会话一样长。所以,唉,看来您必须先声明该表,然后再填充它。编写和支持的代码可能很笨拙,但它会足够高效地执行。

              【讨论】:

              • 我的回答既没有说也没有推荐使用动态SQL——事实上,它表明动态SQL不能用于解决问题,并得出结论,具体声明数据插入之前的临时表可能是要走的路。
              • 您可以使用动态 SQL 并插入到全局临时表 (##MyTesttable) 中,然后删除全局表。将添加为单独的答案
              【解决方案8】:

              在这两种情况下,您都可以在 SELECTing INTO 之前删除该表。例如:

              DECLARE @Id int 
              SET @Id = 1  
              
              IF (@Id = 2) BEGIN  
                  IF OBJECT_ID('tempdb..#MyTestTable') IS NOT NULL DROP TABLE #MyTestTable
                  SELECT 'ABC' AS Letters 
                  INTO #MyTestTable; 
              END ELSE BEGIN 
                  IF OBJECT_ID('tempdb..#MyTestTable') IS NOT NULL DROP TABLE #MyTestTable 
                  SELECT 'XYZ' AS Letters 
                  INTO #MyTestTable; 
              END 
              

              评论后更新:

              这很烦人。

              两个单独的临时表怎么样?然后在 If/Else 登录后,检查每个是否存在,如果存在,则选择第三个临时表?这可能效果不佳,但这是否重要取决于您需要它的用途。

              【讨论】:

              • 我试过了。我将IF OBJECT_ID('tempdb..#MyTestTable') IS NOT NULL DROP TABLE #MyTestTable 放在INSERT INTO 语句之前的每个块中,但结果相同。
              • 不是我。但也许是因为您的建议也没有通过语法检查?我认为 2 个单独的临时表开始比在 IF/ELSE 之前创建临时表做更多的工作。
              • 是的,在逻辑之前创建临时表似乎是最好的选择,但是如果不知道更多关于你在做什么,很难明确地说出来。
              【解决方案9】:

              在您提供的场景中,您可以这样做

              DECLARE @Id int
              SET @Id = 1
              
              IF OBJECT_ID('tempdb..#MyTestTable') IS NOT NULL DROP TABLE #MyTestTable
              
              SELECT 
                CASE WHEN (@Id = 2) 
                  THEN 'ABC' 
                  ELSE 'XYZ' 
                END AS Letters
              INTO #MyTestTable;
              

              但否则您需要像这样在if statement 之前创建表

              Create Table #MyTestTable (
                MyValue varchar(3)
              )
              IF (@Id = 2) BEGIN 
                Insert Into (MyValue)
                SELECT 'ABC' AS Letters;
              END ELSE BEGIN
                Insert Into (MyValue)
                SELECT 'XYZ' AS Letters;
              END
              

              【讨论】:

              • 是的,对于这种可行的方案。但实际的查询要复杂得多。
              猜你喜欢
              • 2015-11-30
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2017-11-16
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              相关资源
              最近更新 更多