SQL 在 If 和 Else 块中插入临时表

发布于 2024-10-01 10:17:13 字数 607 浏览 9 评论 0原文

我正在尝试根据 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 语句,但该表将有很多列,我正在尝试做到高效。这是唯一的选择吗?或者有什么方法可以让这项工作发挥作用吗?

谢谢, 马特

I'm trying to populate a temp table based on the result of a condition in SQL 2005. The temp table will have the same structure either way, but will be populated using a different query depending on the condition. The simplified example script below fails in syntax checking of the ELSE block INSERT INTO with the error of:

There is already an object named
'#MyTestTable' in the database.

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

I could create the temp table before the IF/ELSE statement and then just do INSERT SELECT statements in the conditional blocks, but the table will have lots of columns and I was trying to be efficient about it. Is that the only option? Or is there some way to make this work?

Thanks,
Matt

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(9

玻璃人 2024-10-08 10:17:14

迟到了 8 年才回答,但令我惊讶的是没有人想到:

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

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

简单、快捷。不需要动态sql。

编辑:正如 Sushant 在评论中所说,Select top 0 也可以在 T-SQL 中工作,并且对大多数人来说看起来有点“更好”。话虽这么说,它的性能与 1=2 的情况完全相同(通过查询规划器验证),因此请根据需要进行选择。

Answering 8 years late, but I'm surprised nobody thought of:

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

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

Simple and quick. No dynamic sql needed.

EDIT: As Sushant said in the comments, Select top 0 will also work in T-SQL and it looks a bit 'better' to most. That being said, its performance is the exact same as where 1=2 (verified with query planner) so choose as you please.

太傻旳人生 2024-10-08 10:17:14

您遇到的问题不是您正在填充临时表,而是您正在尝试创建该表。 SQL 解析您的脚本并发现您正在尝试在两个不同的位置创建它,因此会引发错误。意识到“执行路径”不可能同时命中两个创建语句还不够聪明。使用动态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

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

The problem you’re having is not that you are populating the temp table, but that you’re trying to create the table. SQL parses your script and finds that you are attempting to create it in two different places, and so raises an error. It is not clever enough to realize that the “execution path” cannot possibly hit both of the create statemements. Using dynamic SQL will not work; I tried

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

but the temp table only lasts as long as the dynamic session. So, alas, it looks like you’ll have to first declare the table and then populate it. Awkward code to write and support, perhaps, but it will perform efficiently enough.

宁愿没拥抱 2024-10-08 10:17:14

在您提供的场景中,您可以执行此操作

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 语句 之前创建表,如下所示

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

In the scenario you provide you could do this

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;

But otherwise you will need to create the table before the if statement like this

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
以酷 2024-10-08 10:17:14

如果无法预先创建临时表并且不想将核心逻辑放入动态 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

Here is a solution which I use if temp table can't be created upfront and don't want to put core logic in dynamic 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
丶视觉 2024-10-08 10:17:14

在这两种情况下,您可以在 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 登录后,检查每个临时表是否存在,如果存在,则选择第三个临时表?这可能表现不佳,但这是否重要取决于您需要它的用途。

You could drop the table before SELECTing INTO it in both cases., e.g.:

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 

Update After Comment:

That's annoying.

How about two separate temp tables? Then after the If/Else login, check for the existence of each one and if it exists, select into a third temp table? That may not perform great, but whether that matters or not depends on what you need this for.

不必了 2024-10-08 10:17:14

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

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

This is an old issue, but for anyone else coming here:

The dynamic SQL answer given by user Philip Kelley does not work for local temp tables (#Mytemp). What you can do is create dynamic SQL to insert it into a global temp table (##MyTemp) which can later be dropped.

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
仅一夜美梦 2024-10-08 10:17:14

我尝试了这个:

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,则此解决方案会更好,因为否则您必须在重新运行脚本之前物理删除它,这在测试条件下很烦人。

I tried this:

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

This solution is better if later you need to add columns to #MyTestTable, because otherwise you must physically drop it before you re-run your script, which is annoying iin test conditions.

如梦初醒的夏天 2024-10-08 10:17:14

这段代码可以帮助你

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

this code may help you

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

this code works in sql server 2014
i don't know if it works in sql 2005 or not

森林散布 2024-10-08 10:17:14

你可以试试这个代码。

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

谢谢!!!

You can try this code.

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

Thanks!!!

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文