簡體   English   中英

SQL 在 If 和 Else 塊中插入臨時表

[英]SQL Insert Into Temp Table in both If and Else Blocks

我正在嘗試根據 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語句,但該表將有很多列,我試圖提高效率。 這是唯一的選擇嗎? 或者有什么方法可以使這項工作?

謝謝,馬特

回答晚了 8 年,但我很驚訝沒有人想到:

select * into #MyTempTable from...
where 1=2

IF -- CONDITION HERE
insert into #MyTempTable select...
ELSE
insert into #MyTempTable select...

簡單,快速,而且有效。 不需要動態sql

您遇到的問題不是您正在填充臨時表,而是您正在嘗試創建該表。 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

但臨時表的持續時間與動態會話一樣長。 所以,唉,看來您必須先聲明該表,然后再填充它。 編寫和支持的代碼可能很笨拙,但它的執行效率足夠高。

在您提供的場景中,您可以執行此操作

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

如果無法預先創建臨時表並且不想將核心邏輯放在動態 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

這是一個老問題,但對於來到這里的其他人:

用戶 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

此代碼可以幫助您

--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

我試過這個:

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 添加列,此解決方案會更好,因為否則您必須在重新運行腳本之前物理刪除它,這在測試條件下很煩人。

你可以試試這個代碼。

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

謝謝!!!

在這兩種情況下,您都可以在 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 登錄后,檢查每個是否存在,如果存在,則選擇進入第三個臨時表? 這可能表現不佳,但這是否重要取決於您需要它做什么。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM