1

This stored procedure creates a table in the database when I make the select * into, and because of that, when there is more than one user, an error appears and says SearchTMP table already exists, this happens even if I make a drop of that table. So I decided to make a temporary table, as the following code shows:

INSERT INTO @SQLTbl(Tablename, WHEREClause) 
SELECT QUOTENAME(SCh.name) + '.' + QUOTENAME(ST.NAME), 
    ( 
        SELECT '[' + SC.Name + ']' + ' LIKE ''' + REPLACE(SearchSTR.SearchString,'''','''''') + ''' OR ' + CHAR(10) 
            FROM SYS.columns SC 
            JOIN SYS.types STy 
            ON STy.system_type_id = SC.system_type_id 
            AND STy.user_type_id =SC.user_type_id 
            CROSS JOIN @SearchStringTbl SearchSTR 
        WHERE STY.name in ('varchar','char','nvarchar','nchar','text') 
        AND SC.object_id = ST.object_id 
        ORDER BY SC.name 
        FOR XML PATH('') 
    ) 
FROM  SYS.tables ST 
JOIN @CheckTableNames chktbls 
ON chktbls.Tablename = ST.name  
JOIN SYS.schemas SCh 
ON ST.schema_id = SCh.schema_id 
AND Sch.name = chktbls.Schemaname 
WHERE ST.name <> '#MyTempTable' -- it was SearchTMP
GROUP BY ST.object_id, QUOTENAME(SCh.name) + '.' +  QUOTENAME(ST.NAME);

UPDATE @SQLTbl SET SQLStatement = 'SELECT * INTO #MyTempTable FROM ' + Tablename + ' WHERE ' + substring(WHEREClause,1,len(WHEREClause)-5)

Since I didn't want to declare or create the table previously, the temptable will be created in the select * into. But when I try to run the procedure by filling the parameters it says:

>Msg 208, Level 16, State 0, Procedure SP_SearchTables_TEST, Line 265, Invalid object name #MyTempTable

The entire stored procedure:

ALTER PROCEDURE [dbo].[SearchTables_TEST]  @SearchStr NVARCHAR(60)  ,@GenerateSQLOnly Bit = 0  ,@SchemaNames VARCHAR(500) ='%'  AS

SET NOCOUNT ON 

DECLARE @MatchFound BIT 

SELECT @MatchFound = 0 

DECLARE @CheckTableNames Table 
( 
Schemaname sysname 
,Tablename sysname 
) 

DECLARE @SearchStringTbl TABLE 
( 
SearchString VARCHAR(500) 
) 

DECLARE @SQLTbl TABLE 
( 
 Tablename        SYSNAME 
,WHEREClause    VARCHAR(MAX) 
,SQLStatement   VARCHAR(MAX) 
,Execstatus        BIT  
) 

DECLARE @SQL VARCHAR(MAX) 
DECLARE @TableParamSQL VARCHAR(MAX) 
DECLARE @SchemaParamSQL VARCHAR(MAX) 
DECLARE @TblSQL VARCHAR(MAX) 
DECLARE @tmpTblname sysname 
DECLARE @ErrMsg VARCHAR(100)    

IF LTRIM(RTRIM(@SchemaNames)) ='' 
BEGIN 

    SELECT @SchemaNames = '%' 
END

IF CHARINDEX(',',@SchemaNames) > 0  
    SELECT @SchemaParamSQL = 'SELECT ''' + REPLACE(@SchemaNames,',','''as SchemaName UNION SELECT ''') + '''' 
ELSE 
    SELECT @SchemaParamSQL = 'SELECT ''' + @SchemaNames + ''' as SchemaName ' 

    SELECT @TblSQL = 'SELECT SCh.NAME,T.NAME 
              FROM SYS.TABLES T 
              JOIN SYS.SCHEMAS SCh 
              ON SCh.SCHEMA_ID = T.SCHEMA_ID 
              INNER JOIN [DynaForms].[dbo].[Enums_Tables] et on 
                 (et.Id = T.NAME COLLATE Latin1_General_CI_AS)  '

    INSERT INTO @CheckTableNames 
    (Schemaname,Tablename) 
    EXEC(@TblSQL)  

IF NOT EXISTS(SELECT 1 FROM @CheckTableNames) 
BEGIN 

    SELECT @ErrMsg = 'No tables are found in this database ' + DB_NAME() + ' for the specified filter' 
    PRINT @ErrMsg 
    RETURN 

END  

IF LTRIM(RTRIM(@SearchStr)) ='' 
BEGIN 

    SELECT @ErrMsg = 'Please specify the search string in @SearchStr Parameter' 
    PRINT @ErrMsg 
    RETURN 
END 
ELSE 
BEGIN  
    SELECT @SearchStr = REPLACE(@SearchStr,',,,',',#DOUBLECOMMA#') 
    SELECT @SearchStr = REPLACE(@SearchStr,',,','#DOUBLECOMMA#') 

    SELECT @SearchStr = REPLACE(@SearchStr,'''','''''') 

    SELECT @SQL = 'SELECT ''' + REPLACE(@SearchStr,',','''as SearchString UNION SELECT ''') + ''''  

    INSERT INTO @SearchStringTbl 
    (SearchString) 
    EXEC(@SQL) 

    UPDATE @SearchStringTbl 
       SET SearchString = REPLACE(SearchString ,'#DOUBLECOMMA#',',') 
END     

INSERT INTO @SQLTbl(Tablename,WHEREClause) 
SELECT QUOTENAME(SCh.name) + '.' + QUOTENAME(ST.NAME), 
( 
    SELECT '[' + SC.Name + ']' + ' LIKE ''' + REPLACE(SearchSTR.SearchString,'''','''''') + ''' OR ' + CHAR(10) 
        FROM SYS.columns SC 
        JOIN SYS.types STy 
        ON STy.system_type_id = SC.system_type_id 
        AND STy.user_type_id =SC.user_type_id 
    CROSS JOIN @SearchStringTbl SearchSTR 
    WHERE STY.name in ('varchar','char','nvarchar','nchar','text') 
    AND SC.object_id = ST.object_id 
    ORDER BY SC.name 
    FOR XML PATH('') 
) 
FROM  SYS.tables ST 
JOIN @CheckTableNames chktbls 
ON chktbls.Tablename = ST.name  
JOIN SYS.schemas SCh 
ON ST.schema_id = SCh.schema_id 
AND Sch.name = chktbls.Schemaname 
WHERE ST.name <> '#MyTempTable' -- it was SearchTMP
GROUP BY ST.object_id, QUOTENAME(SCh.name) + '.' +  QUOTENAME(ST.NAME);    

UPDATE @SQLTbl SET SQLStatement = 'SELECT * INTO #MyTempTable FROM ' + Tablename + ' WHERE ' + substring(WHEREClause,1,len(WHEREClause)-5)

DELETE FROM @SQLTbl 
WHERE WHEREClause IS NULL 

DECLARE @output TABLE (Id VARCHAR(50), Name VARCHAR(100))   

WHILE EXISTS (SELECT 1 FROM @SQLTbl WHERE ISNULL(Execstatus ,0) = 0) 
BEGIN       

    SELECT TOP 1 @tmpTblname = Tablename , @SQL = SQLStatement 
    FROM @SQLTbl  
    WHERE ISNULL(Execstatus ,0) = 0 

    IF @GenerateSQLOnly = 0 
    BEGIN 

        IF OBJECT_ID('#MyTempTable','U') IS NOT NULL -- this line was uncomment
         DROP TABLE #MyTempTable   -- this line was uncomment


        EXEC (@SQL)      


        IF EXISTS(SELECT 1 FROM #MyTempTable) -- It was like this: SearchTMP
        BEGIN 
            SELECT @MatchFound = 1 

            INSERT INTO @output (Id, Name)
            Select * from [DynaForms].[dbo].[Enums_Tables] where id in (SELECT parsename(@tmpTblname,1) FROM #MyTempTable) -- It was like this: SearchTMP
        END 

     END 
     ELSE 
     BEGIN 
         PRINT REPLICATE('-',100) 
         PRINT @tmpTblname 
         PRINT REPLICATE('-',100) 
         PRINT replace(@SQL,'INTO #MyTempTable','') 
     END 

     UPDATE @SQLTbl 
        SET Execstatus = 1 
      WHERE Tablename = @tmpTblname 

END 

SELECT * FROM @output

IF @MatchFound = 0  
BEGIN 
    SELECT @ErrMsg = 'No Matches are found in this database ' + DB_NAME() + ' for the specified filter' 
    PRINT @ErrMsg 
    RETURN 
END 

SET NOCOUNT OFF 
Ali Azam
  • 2,047
  • 1
  • 16
  • 25
Aires Menezes
  • 85
  • 1
  • 15
  • Might be worth adding some `PRINT(@SQL);` lines in, and seeing what is being run prior to it. The message states that the error occurs on line 265, however, there's only 192 in that SQL you've run, so difficult to work out where it's going wrong (as we can't run your SQL as it references other objects). What lines is it actually failing at? – Thom A Jan 02 '18 at 12:21
  • This post may help you out, see answer #2. https://stackoverflow.com/questions/662049/dynamic-sql-results-into-temp-table-in-sql-stored-procedure – DragonZero Jan 02 '18 at 12:22
  • @Larnu there's only 192 lines because I deleted commented lines that were only making the stored procedure bigger and harder to read. But the entire code is there. Line 265 is the IF OBJECT_ID('tempdb.dbo.#MyTempTable','U'). – Aires Menezes Jan 02 '18 at 13:50
  • There's nothing wrong with that line, which causes me to think it's probably the line afterwards: `DROP TABLE #MyTempTable`. What version of SQL Server are you using? If you're using 2016+, you could use `DROP TABLE IF EXISTS #MyTempTable;` – Thom A Jan 02 '18 at 13:58
  • @Larnu I'm using sqlserver 2012. Even if I comment drop table if exits, it still gives the error and even if I comment OBJECT_ID('tempdb.dbo.#MyTempTable','U'), it will also give the same error. Maybe it's not creating the table at all? (In the select into). – Aires Menezes Jan 02 '18 at 14:04
  • Like i said above then, i'd suggest adding some `PRINT (@SQL);` statements in, and see what the actual value is, and what it's trying to run. it might, suddenly, be quite apparent to you. – Thom A Jan 02 '18 at 14:06
  • /facepalm can't believe I didn't notice why this was failing (I blame 2018!). Answer posted. – Thom A Jan 02 '18 at 14:10
  • @Larnu Thanks for the answer, but I still have some doubts, I commented in your answer, could you please help a little bit more? – Aires Menezes Jan 02 '18 at 14:56
  • not sure what your doubts are? What I've stated can easily be tested by running the sample script I posted. – Thom A Jan 02 '18 at 15:57
  • @Larnu I was just pointing out the comment I did on your answer. I will try what you said. Thank you again. – Aires Menezes Jan 03 '18 at 10:04

2 Answers2

4

OK, so a quick test actually answered this, and i can't believe I missed this (/facepalm). you can't use a INTO clause with dynamic SQL and a Temporary table and reference it afterwards; you need to CREATE the table. Consider the following:

DECLARE @SQL varchar(max);

SET @SQL = 'SELECT 1 AS A, 2 AS B INTO #test;';
EXEC (@SQL);
SELECT *
FROM #test;
DROP TABLE #test;

This returns the error:

Msg 208, Level 16, State 0, Line 5

Invalid object name '#test'.

And now, for the correct way:

DECLARE @SQL varchar(max);

CREATE TABLE #test (A int, B int);

SET @SQL = 'INSERT INTO #test SELECT 1 AS A, 2 AS B';
EXEC (@SQL);
SELECT *
FROM #test;
DROP TABLE #test;

This works fine. Thus, you need to CREATE your temporary table, not use an INTO clause.

Community
  • 1
  • 1
Thom A
  • 88,727
  • 11
  • 45
  • 75
  • Thanks for the answer, but I would like some adicional information in how to implement in my case. Because I have this code UPDATE @SQLTbl SET SQLStatement = 'SELECT * INTO #MyTempTable FROM ' + Tablename + ' WHERE ' + substring(WHEREClause,1,len(WHEREClause)-5). In which previously would create a table in the database, so I changed to a temp table. But I don't know what columns it will have, so the reason why i used select * into, was to have the columns of the Tablename. So is there any way to create a temp table, without having to create the columns first? – Aires Menezes Jan 02 '18 at 14:29
  • Temporary tables created in Dynamic SQL only persist within that statement. So even doing something like `EXEC sp_executesql 'CREATE TABLE #test (ID int);'; SELECT * FROM #Test;` won't work. Added dynamic columns makes things even worse. You could consider making a uniquely named "sudo" temporary table. Maybe using the current user and date & time. I.e. `DECLARE @TempTableName nvarchar(60); SET @TempTableName = 'temp.Table_' + CURRENT_USER + '_' + REPLACE(REPLACE(REPLACE(CONVERT(varchar(25), GETDATE(),120),' ','_'),'-','_'),':',''); PRINT @TempTableName;` (note the use of a schema `temp`). – Thom A Jan 02 '18 at 15:16
0

Instead of

Object_Id('#MyTempTable','U')

You need to use

Object_Id('tempdb..#MyTempTable','U')

To get the object_id of the temporary table to check if it exists or not.

Temp tables are created in TempDB system database

Eralper
  • 6,461
  • 2
  • 21
  • 27
  • Thank you for answering so quickly, but I changed that piece of code and I still says the same error, and in the same line. – Aires Menezes Jan 02 '18 at 13:52