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
Related
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;
I'm trying to create a function that return a table variable.So firstly i get data from Table1 and put it in another table variable. Here i want check if this variable isempty the function return the parameter result else return the result of the table variable
The function script is bellow :
USE[DATABase1]
GO
IF OBJECT_ID (N'CodeFunc', N'TF') IS NOT NULL DROP FUNCTION dbo.CodeFunc;
GO
CREATE FUNCTION CodeFunc ( #Code nvarchar(4) , #Table nvarchar(40) = '' )
RETURNS #VirtualDAT TABLE
(
RowID INT IDENTITY ( 1 , 1 ),
Code nvarchar(400)
)
AS
BEGIN
DECLARE #CodeM nvarchar(400)
DECLARE #imax INT SET #imax = ##ROWCOUNT
DECLARE #i INT SET #i = 1
DECLARE #SelectDAT TABLE
(
RowID INT IDENTITY ( 1 , 1 ),
Code nvarchar(400)
)
INSERT #SelectDAT
SELECT Code FROM table1
WHERE table1.id = 41
IF(EXISTS (SELECT 1 FROM #SelectDAT))
BEGIN
WHILE (#i <= #imax)
BEGIN
SELECT #CodeM = Code FROM #SelectDAT WHERE RowID = #i
INSERT INTO #VirtualDAT(Code) VALUES (#CodeM)
SET #i = #i + 1
END
END
ELSE
INSERT INTO #VirtualDAT(Code) VALUES (#Code)
RETURN
END
So this script works without put it inside function.
And i test this function like this :SELECT * FROM dbo.CodeFunc( 'toto',Default ) the result is :
IF(EXISTS (SELECT 1 FROM #SelectDAT)) no record returned
esle the result is ok
As VR46 says. The ##ROWCOUNT will be set to 0 because there is no query before it. Any code executing in a function happens as a seperate set of queries. It was probably returning a value outside the function because you had previously used the query window for another unrelated query
You could re-factor this function quite dramatically. Look below, ##ROWCOUNT will work here as it is just after the insert query and will definitely have a value based on the insert.
I have not been able to test this, but I think something like this should do the same job.
USE[DATABase1]
GO
IF OBJECT_ID (N'CodeFunc', N'TF') IS NOT NULL DROP FUNCTION dbo.CodeFunc;
GO
CREATE FUNCTION CodeFunc ( #Code nvarchar(4) , #Table nvarchar(40) = '' )
RETURNS #VirtualDAT TABLE
(
RowID INT IDENTITY ( 1 , 1 ),
Code nvarchar(400)
)
AS
BEGIN
insert into #VirtualDAT
Select Code from table1 where table1.id = 41
if ##ROWCOUNT = 0
begin
INSERT INTO #VirtualDAT(Code) VALUES (#Code)
end
RETURN
END
Since you are assigning #imax with ##ROWCOUNT right after declaration of variable will be initialized with zero.
From MSDN ##ROWCOUNT
Returns the number of rows affected by the last statement.
If am not wrong you need to assign value to #imax after the insert into..select query.
INSERT #SelectDAT
SELECT Code FROM table1
WHERE table1.id = 41
SET #imax= ##ROWCOUNT
You can do the same in SET BASED APPROACH without using while loop.
CREATE FUNCTION Codefunc (#Code NVARCHAR(4),
#Table NVARCHAR(40) = '')
returns #VirtualDAT TABLE (
rowid INT IDENTITY ( 1, 1 ),
code NVARCHAR(400))
AS
BEGIN
IF EXISTS (SELECT code
FROM table1
WHERE table1.id = 41)
BEGIN
INSERT INTO #VirtualDAT
(code)
SELECT code
FROM table1
WHERE table1.id = 41
END
ELSE
INSERT INTO #VirtualDAT
(code)
VALUES (#Code)
RETURN
END
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.
When I execute my code it works but my data repeats itself. The print is just to see what it gets.
DECLARE #Variable1 NVARCHAR(MAX)
DECLARE #Variable2 NVARCHAR(MAX)
DECLARE #Variable3 NVARCHAR(MAX)
CREATE TABLE #Temp1 (MAI_ID BIGINT, FUN_ID BIGINT)
CREATE TABLE #tmp2 (MAI_ID BIGINT, Variable1 NVARCHAR(MAX),Variable2 NVARCHAR(MAX), Variable3 NVARCHAR(MAX))
INSERT INTO #Temp1
SELECT TOP 10 ISD_MainID, ISNULL(ISD_FUNID,0)
FROM [dev_SAB_EM].[dbo].[SiteDetails]
ORDER BY ISD_ID DESC
DECLARE #MAI_ID BIGINT
DECLARE #FUN_ID BIGINT
WHILE (SELECT COUNT(MAI_ID) FROM #Temp1) <> 0
BEGIN
SELECT TOP 1 #MAI_ID = MAI_ID, #FUN_ID = FUN_ID FROM #Temp1
PRINT #MAI_ID
PRINT #FUN_ID
SELECT #Variable1 = ISNULL(FUN_Name,'') FROM [dev_SAB_Man].[dbo].[fx_GetFUNStructureCTE_Asc] (#FUN_ID) WHERE FUN_Level = 1
SELECT #Variable2 = ISNULL(FUN_Name,'') FROM [dev_SAB_Man].[dbo].[fx_GetFUNStructureCTE_Asc] (#FUN_ID) WHERE FUN_Level = 2
SELECT #Variable3 = ISNULL(FUN_Name,'') FROM [dev_SAB_Man].[dbo].[fx_GetFUNStructureCTE_Asc] (#FUN_ID) WHERE FUN_Level = 3
INSERT INTO #tmp2(MAI_ID, Variable1, Variable2, Variable3)
SELECT #MAI_ID, #Variable1, #Variable2, #Variable3
DELETE FROM #Temp1 WHERE MAI_ID = #MAI_ID AND FUN_ID = #FUN_ID
END
SELECT * FROM #tmp2
DROP TABLE #Temp1
DROP TABLE #tmp2
fx_GetFUNStructureCTE_Asc
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE FUNCTION [dbo].[fx_GetFUNStructureCTE_Asc] (#param_FUNID int)
RETURNS #FUN_Names table
(
[Level_Label] nvarchar(255),
[FUN_Name] nvarchar(255),
[FUN_Level] int,
[FUN_ID] int
)
AS
BEGIN
with cte([Level_Label],[FUN_Name],[FUN_Level],[FUN_ID],[FUN_FUNID]) as
(
select ful1.FUL_Name,fu1.FUN_Name,fu1.FUN_Level,fu1.FUN_ID,fu1.FUN_FUNID
from FunctionalUnits fu1
inner join FunctionalUnitLevels ful1 on ful1.FUL_Level=fu1.FUN_Level
where fu1.FUN_ID=#param_FUNID
union all
select ful2.FUL_Name,fu2.FUN_Name,fu2.FUN_Level,fu2.FUN_ID,fu2.FUN_FUNID
from FunctionalUnits fu2
inner join FunctionalUnitLevels ful2 on ful2.FUL_Level=fu2.FUN_Level
inner join CTE a on a.FUN_FUNID=fu2.FUN_ID
)
insert into #FUN_Names
([Level_Label],[FUN_Name],[FUN_Level],[FUN_ID])
(select [Level_Label],[FUN_Name],[FUN_Level],[FUN_ID] from cte
where exists (select FUA_isActive from FunctionalUnitsActive where FUA_isActive=1))
return
RETURN
END
GO
Any suggestions or anything that can hep me?
Ok I've added fx_GetFUNStructureCTE_Asc
Considering the informations you gave, besides what #Lamak said, it also may depend on what the the field ISD_FUNID values has on [dev_SAB_EM].[dbo].[SiteDetails] table. If they are all the same on every record then there's no problem with your code...
But, it's a basic assumption...
And, assuming what you said on your comment as the value of ISD_FUNID being NULL, what may be happening is this: when all the value of the field FUN_ID are 0 on table #Temp1 what will happen when you execute the query on the function [dev_SAB_Man].[dbo].[fx_GetFUNStructureCTE_Asc] is that all rows will loop while the assignment occurs, setting the variables values to the last one returned by the function.
It'll make all the variables values be the same for all #tmp2 rows. You may need to improve the function call to return just one value.
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 ...