T-SQL error object exists when separated in if/else blocks - sql-server-2005

I get the error: Msg 2714, Level 16, State 1, Line 16
There is already an object named '#mytemptable' in the database.
There are ways around it, but wonder why this happens. Seems like SQL Server is verifying both blocks of the if/else statement?
declare #choice int
select #choice = 1
if #choice = 1
begin
select 'MyValue = 1' AS Pick into #my_temp_table
end
else
begin
select 'MyValue <> 1' AS Pick into #my_temp_table
end
select * from #my_temp_table
drop table #my_temp_table
If the tables have different names, it works. Or if I create the temp table and use Insert Into... statements that works as well.

See here: What is deferred name resolution and why do you need to care?
basically you need to ceate the table first
So what is happening is that beginning with SQL server 7 deferred name resolution was enabled for real tables but not for temporary tables. If you change the code to use a real table instead of a temporary table you won’t have any problem
Here is another way
declare #choice int
select #choice = 1
declare #Value varchar(100)
if #choice = 1
select #Value = 'MyValue = 1'
else
select #Value = 'MyValue <> 1'
select #Value AS Pick into #my_temp_table
select * from #my_temp_table
drop table #my_temp_table

Try this:
declare #choice int
select #choice = 1
CREATE TABLE #my_temp_table(
Pick varchar(25)
)
if #choice = 1
begin
INSERT INTO #my_temp_table
select 'MyValue = 1'
end
else
begin
INSERT INTO #my_temp_table
select 'MyValue <> 1'
end
select * from #temptable
drop table #temptable
EDIT Sorry, I see that you tried this and the question was WHY does this happen. It is because SQL Server parses the stored procedure when it is created and checks for naming conflicts.

Related

There is already an object named '#BaseData' in the database

Below is a snippet of my code.
I am wanting to filter my data based upon a variable.
When I try to run the code, it returns an error of "There is already an object named '#BaseData' in the database.". I am not sure as to why this is the case; I have put extra checks within the IF statements to drop the temp table if it already exists but to no avail.
Are you able to help or provide an alternative solution please?
DECLARE #Variable AS VARCHAR(20) = 'Example1'
IF OBJECT_ID(N'TEMPDB..#BaseData') IS NOT NULL
DROP TABLE #BaseData
IF #Variable = 'Example1'
BEGIN
SELECT
*
INTO
#BaseData
FROM
[Database].[schema].[table]
END
IF #Variable = 'Example2'
BEGIN
SELECT
*
INTO
#BaseData
FROM
[Database].[schema].[table]
WHERE
[column] = 1
END
IF #Variable = 'Example3'
BEGIN
SELECT
*
INTO
#BaseData
FROM
[Database].[schema].[table]
WHERE
[column] = 0
END
While code is compiled by SQL, creation of same #table is found in each condition so it doesn't work.
One possible solution would be to create table and than insert data conditionally.
-- DROP TEMP TABLE IF EXISTS
IF OBJECT_ID(N'TEMPDB..#BaseData') IS NOT NULL
DROP TABLE #BaseData
GO
-- CRATE TEMP TABLE WITH TempId, AND SAME STRUCTURE AS YOUR TABLE
SELECT TOP 0 CONVERT(INT, 0)TempId, * INTO #BaseData FROM TestTable
-- DECLARE VARIABLE
DECLARE #Variable AS VARCHAR(20)= 'Example1'
-- INSERT DATA IN TABLE DEPENDING FROM CONDITION
IF (#Variable = 'Example1')
BEGIN
INSERT INTO #BaseData SELECT * FROM TestTable
END
IF (#Variable = 'Example2')
BEGIN
INSERT INTO #BaseData SELECT * FROM TestTable WHERE Id = 1
END
IF (#Variable = 'Example3')
BEGIN
INSERT INTO #BaseData SELECT * FROM TestTable WHERE Id = 2
END

Switch case with storing results into same table in SQL

I want to store the results into table with same name as per the condition. How to achieve the same ? Following is the code:
While executing it throws error that #a already exists.
IF #Input ='1'
BEGIN
drop #a
SELECT *
INTO #a
FROM table1
END;
ELSE IF #Input ='2'
BEGIN
drop #a
SELECT *
INTO #a
FROM table2
END;
You can use this solution using a global temporary table (maybe not the best / safest solution). The statements get executed with EXECUTE:
DECLARE #Input VARCHAR(20) = '1'
IF OBJECT_ID('tempdb..##a') IS NOT NULL
BEGIN
DROP TABLE ##a
END
IF #Input = '1'
EXEC ('SELECT * INTO ##a FROM table1;')
ELSE IF #Input = '2'
EXEC ('SELECT * INTO ##a FROM table2;')
-- you can implement steps here to create a local temporary table.
-- see: https://stackoverflow.com/questions/9534990/tsql-select-into-temp-table-from-dynamic-sql
SELECT * FROM ##a
Also have a look at this question: TSQL select into Temp table from dynamic sql. There is also described how you can get the data as local temporary table in two different ways (using a global temporary table or a view).
The problem using the EXECUTE function is leaving the scope.
try this
if object_id('tempdb..#a') is not null
drop table #a
IF #Input ='1'
BEGIN
SELECT *
INTO #a
FROM table1
END;
ELSE IF #Input ='2'
BEGIN
SELECT *
INTO #a
FROM table2
END;

T-SQL If Else condition on the same Temp Table

Here is what I am trying to do:
IF len(Variable) > 1
BEGIN
SELECT * INTO #TEMPTAB FROM multiple joins
END
ELSE
BEGIN
SELECT * INTO #TEMPTAB FROM different multiple joins
END
SELECT * FROM #TEMPTAB more large number of multiple joins & where & groupby
ERROR: There is already an object #TEMPTAB defined
-- Because of select * into in IF and ELSE both
I don't want to create a temp table prior cause it has a lot of columns to be defined.
Is there a way around it?
This was a fun problem for me that is... Well I figured out four ways to do it. One is with a view, one with a temp Table, one with a physical table, and one with a stored procedure and global temp table. Let me know if you have any questions.
View
DECLARE #Variable VARCHAR(10) = 'aa';
IF LEN(#Variable) > 1
BEGIN
EXEC('CREATE VIEW yourView AS SELECT ''Greater than 1'' col')
END
ELSE
BEGIN
EXEC('CREATE VIEW yourView AS SELECT ''Less than 1'' col')
END
SELECT *
FROM yourView;
DROP VIEW yourView;
Temp Table
DECLARE #Variable VARCHAR(100) = 'aa',
--Default value is 0
#percent INT = 0;
--If the length > 1, then change percent to 100 as to return the whole table
IF LEN(#Variable) > 1
SET #percent = 100;
--If the length <=1, then #percent stays 0 and you return 0 percent of the table
SELECT TOP(#percent) PERCENT 'Greater than 1' col INTO #TEMPTAB
--If you didn't populate the table with rows, then use this query to populate it
IF(#percent = 0)
BEGIN
INSERT INTO #TEMPTAB
SELECT 'Less than 1' col
END
/*your 1k lines of code here*/
SELECT *
FROM #TEMPTAB
--Cleanup
DROP TABLE #tempTab
Physical Table
DECLARE #Variable VARCHAR(10) = 'A';
IF len(#Variable) > 1
BEGIN
SELECT 'Greater than 1' col INTO TEMPTAB
END
ELSE
BEGIN
SELECT 'Less than 1' col INTO TEMPTAB2
END
IF OBJECT_ID('TEMPTAB2') IS NOT NULL
--SP_Rename doesn't work on temp tables so that's why it's an actual table
EXEC SP_RENAME 'TEMPTAB2','TEMPTAB','Object'
SELECT *
FROM TEMPTAB
DROP TABLE TEMPTAB;
Stored Procedure with Global Temp Table
IF OBJECT_ID('yourProcedure') IS NOT NULL
DROP PROCEDURE yourProcedure;
GO
CREATE PROCEDURE yourProcedure
AS
IF OBJECT_ID('tempdb..##TEMPTAB') IS NOT NULL
DROP TABLE ##tempTab;
SELECT 'Greater than 1' col INTO ##TEMPTAB
GO
DECLARE #Variable VARCHAR(10) = 'aaa';
IF LEN(#Variable) > 1
BEGIN
EXEC yourProcedure;
END
ELSE
BEGIN
SELECT 'Less than 1' col INTO ##TEMPTAB
END
SELECT *
FROM ##TEMPTAB
IF OBJECT_ID('tempdb..##TEMPTAB') IS NOT NULL
DROP TABLE ##TEMPTab;
Didn't you consider dynamic query with global temporary tables? This works for me:
DECLARE #sql NVARCHAR(MAX) = CASE WHEN 1 = 2
THEN 'SELECT * INTO ##TEMPTAB FROM dbo.SomeTable1'
ELSE 'SELECT * INTO ##TEMPTAB FROM dbo.SomeTable2'
END
EXEC (#sql)
SELECT * FROM ##TEMPTAB
DROP TABLE ##TEMPTAB
The first time you ran this code it created the table #TEMPTAB. The next time you ran SQL Server is telling you the table already exists. You should precede your code with the following:
if object_ID('tempdb..#TEMPTAB','U') is not null
drop table #TEMPTAB
This will drop (delete the table if it already exists) and the code that follows will always be able to recreate(or create) the table.

T-SQL IF statement explanation

I'm really puzzled by this one!! I'm sure it's simple but really can't figure it out!!
DECLARE #jobid INT = 100
IF (#JobID >= 0)
BEGIN
SELECT * into #tmp FROM Persons
end
ELSE
BEGIN
SELECT * into #tmp FROM Persons1
end
It gives an error that the #tmp table already exists! Why it would validate both statements !
Of course my original query is huge and doing more, but that's a sample to illustrate my error.
Can anybody explain it please?
The #tmp table is not there, even when you try to drop it or change the name, still the engine validates both statements!
I'm using 2008 R2.
Thanks
Jason
You run it over Linked Server? Or you not deleted the one from previous run.
Try to create #tmp table prior to IF statement:
CREATE TABLE #tmp(fields...)
DECLARE #jobid INT = 100
IF (#JobID >= 0)
BEGIN
INSERT #tmp
SELECT * FROM Persons
end
ELSE
BEGIN
INSERT #Tmp
SELECT * FROM Persons1
end
or delete provious one
IF OBJECT_ID('tempdb..#tmp') IS NOT NULL
EXEC('DROP TABLE #tmp')
GO
DECLARE #jobid INT = 100
IF (#JobID >= 0)
BEGIN
SELECT * into #tmp FROM Persons
end
ELSE
BEGIN
SELECT * into #tmp FROM Persons1
end
#tmp may already be created in tempDB from previous runs of your query. If you are not using #tmp anywhere in your query prior to that block, you could do something like the following prior to that block of code to ensure it's always ready to go:
IF OBJECT_ID('tempDB..#tmp') IS NOT NULL
DROP TABLE #tmp

There is already an object named '#columntable' in the database

I am trying the following query
if exists (select 1 from emp where eid = 6)
begin
if object_id('tempdb..#columntable') is not null
begin
drop table #columntable
end
create table #columntable (oldcolumns varchar(100))
end
else
begin
if object_id('tempdb..#columntable') is not null
begin
drop table #columntable
end
create table #columntable (newcolumns varchar(100))
end
But I am getting the error
Msg 2714, Level 16, State 1, Line 8
There is already an object named '#columntable' in the database.
Can anyone suggest why? The same query works fine if I do not write the else part.
This is a SQL Server parser error unfortunately (confirmed by Microsoft).
#DizGrizz is also right - SELECT .. INTO #SomeTable doesn't work if repeated in IF .. ELSE statements.
IF .. ELSE .. CREATE TABLE #SomeTempTable
In answer to the actual question, creating then altering the table works (you also only have to check and drop once)...
IF OBJECT_ID('tempdb..#MyTempTable') IS NOT NULL
BEGIN
DROP TABLE #MyTempTable
END
CREATE TABLE #MyTempTable (DummyColumn BIT)
IF EXISTS (SELECT 1 FROM EMP WHERE EID = 6)
BEGIN
ALTER TABLE #MyTempTable
ADD MyColumnType1 VARCHAR(100)
ALTER TABLE #MyTempTable
DROP COLUMN DummyColumn
END
ELSE
BEGIN
ALTER TABLE #MyTempTable
ADD MyColumnType2 VARCHAR(100)
ALTER TABLE #MyTempTable
DROP COLUMN DummyColumn
END
IF .. ELSE .. SELECT INTO #SomeTempTable
The issue I had however was the same as #DizGrizz: IF .. ELSE combined with SELECT .. INTO #SomeTable fails. As a workaround it's possible to select the top 0 rows (i.e. none) to create the table with the correct column types. (This insulates the script from column type changes and also avoids the pain of declaring every type.) INSERT INTO can then be used, provided IDENTITY_INSERT is set to ON to prevent errors:
IF OBJECT_ID('tempdb..#MyTempTable') IS NOT NULL
DROP TABLE #MyTempTable
-- This creates the table, but avoids having to declare any column types or sizes
SELECT TOP 0 KeyNm
INTO #MyTempTable
FROM dbo.MyDataTable2
-- Required to prevent IDENTITY_INSERT error
SET IDENTITY_INSERT #MyTempTable ON
IF #something = 1
BEGIN
-- Insert the actual rows required into the (currently empty) temp table
INSERT INTO #MyTempTable (KeyNm)
SELECT KeyNm
FROM dbo.MyDataTable2
WHERE CatNum = 2
END
ELSE
BEGIN
-- Insert the actual rows required into the temp table
INSERT INTO #MyTempTable (KeyNm)
SELECT KeyNm
FROM dbo.MyDataTable2
WHERE CatNum = 8
END
SET IDENTITY_INSERT #MyTempTable OFF
Temp tables are not dropped automatically at the end of a query, only when the current connection to the DB is dropped or you explicitly delete them with DROP TABLE #columntable
Either test for the existence of the table at the start of the query or alwayas delete it at the end (preferably both)
EDIT: As Matrin said in his comment, this is actually a parse error. You get the same error if you only parse the SQL as when you execute it.
To test that out I split up your query and tried:
if exists (select 1 from emp where id = 6)
create table #columntable (newcolumns varchar(100))
GO
if not exists (select 1 from emp where id = 6)
create table #columntable (oldcolumns varchar(100))
GO
The parser is happy with that. Interestingly if you change to using non-temp tables the original query parses fine (I realise the problems that would create, I was just interested to find out why the query would not parse).
This also occurs if you create the tables with SELECT INTO...as in
IF OBJECT_ID('tempdb..#MyTempTable', 'U') IS NOT NULL
DROP TABLE #MyTempTable
SELECT TOP 1 #MyVariable = ScaleValue
FROM MyDataTable1
WHERE ProductWeight > 1000
IF #MyVariable = 1
BEGIN
SELECT KeyNm
INTO #MyTempTable
FROM dbo.MyDataTable2
WHERE CatNum = 2
END
ELSE
BEGIN
SELECT KeyNm
INTO #MyTempTable
FROM dbo.MyDataTable2
WHERE CatNum = 8
END
The parser should not even attempt to detect this because, in many cases, it would be impossible for the parser to determine if the table would already exist. The code above is a perfect example...there would be no way for the parser to determine the value of #MyVariable.
I hope that someone has informed MS of this bug (I don't have their ear).
You can check if it exists by doing:
IF OBJECT_ID('tempdb..#columntable') IS NOT NULL
BEGIN
DROP TABLE #columntable
PRINT 'Dropped table...'
END
Use global temp tables and wrap the select in exec.
Example:
Fail
declare #a int = 1
if object_id('tempdb..##temp') is not null drop table ##temp
if(#a = 1) select * into ##temp from table_1
else if(#a = 2) select * into ##temp from table_2
Win
declare #a int = 1
if object_id('tempdb..##temp') is not null drop table ##temp
if(#a = 1) exec('select * into ##temp from table_1')
else if(#a = 2) exec('select * into ##temp from table_2')
This will fool the buggy parser that is trying to be smarter than it is.
And Microsoft - please fix this.
The error is wrong, remove the if clause and it runs through fine. Thus the problem is in the exists:
if object_id('tempdb..#columntable') is not null
begin
drop table #columntable
end
create table #columntable (oldcolumns varchar(100))
Well I got the answer...
As Martin said this is a parse/compile issue. So I Tried changing my script as below
if exists (select 1 from emp where eid = 6)
begin
if object_id('tempdb..#columntable') is not null
begin
drop table #columntable
end
create table #columntable (oldcolumns varchar(100))
end
go
if exists (select 1 from emp where eid = 1)
begin
if object_id('tempdb..#columntable') is not null
begin
drop table #columntable
end
create table #columntable (newcolumns varchar(100))
end
And this worked for me.
I have been experiencing this issue. My query consisted of several joined SELECT statements in the form of:
DROP TABLE IF EXISTS ##TempTableName
SELECT statement ...
So, every time I tried to alter SQL code I would get the above error. I have changed all my temp tables from ##global to #local and now I am able to alter my SQL as many times as needed. So the example above would become:
DROP TABLE IF EXISTS #TempTableName
SELECT statement ...