0

I'm trying to write a stored procedure to search for a string in all tables of a SQL Server database. I was able to find a good stored procedure for this purpose

However I don't want to just put the @Tablenames manually, I want it to go to a table called Enums_Tables that has an ID, and use that ID as @Tablenames.

What I have being thinking to solve this:

I could write another stored procedure to select all Id's from Enums_Tables and execute the first stored procedure, like in here

I could also pass the parameter in C#, since I'm going to use it as a search textbox. But the ideal would be making a single stored procedure.

Could you please help me with this?

EDIT

Thanks to GPW I have been able to solve this problem. I also encountered problems with the collation, but I also solve it. Below is the final stored procedure.

USE [DynaForms]

GO
/****** Object:  stored procedure [dbo].[SP_SearchTables]    Script Date: 09/11/2017 14:59:15 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER PROCEDURE [dbo].[SP_SearchTables] 
 --@Tablenames VARCHAR(500)
 @SearchStr NVARCHAR(60) 
,@GenerateSQLOnly Bit = 0 
,@SchemaNames VARCHAR(500) ='%' 
AS 

/* 
    Parameters and usage 

    @Tablenames        -- Provide a single table name or multiple table name with comma seperated.  
                        If left blank , it will check for all the tables in the database 
                        Provide wild card tables names with comma seperated 
                        EX :'%tbl%,Dim%' -- This will search the table having names comtains "tbl" and starts with "Dim" 

    @SearchStr        -- Provide the search string. Use the '%' to coin the search. Also can provide multiple search with comma seperated 
                        EX : X%--- will give data staring with X 
                             %X--- will give data ending with X 
                             %X%--- will give data containig  X 
                             %X%,Y%--- will give data containig  X or starting with Y 
                             %X%,%,,% -- Use a double comma to search comma in the data 
    @GenerateSQLOnly -- Provide 1 if you only want to generate the SQL statements without seraching the database.  
                        By default it is 0 and it will search. 

    @@SchemaNames    -- Provide a single Schema name or multiple Schema name with comma seperated.  
                        If left blank , it will check for all the tables in the database 
                        Provide wild card Schema names with comma seperated 
                        EX :'%dbo%,Sales%' -- This will search the Schema having names comtains "dbo" and starts with "Sales" 

    Samples : 

    1. To search data in a table 

        EXEC SP_SearchTables @Tablenames = 'T1' 
                         ,@SearchStr  = '%TEST%' 

        The above sample searches in table T1 with string containing TEST. 

    2. To search in a multiple table 

        EXEC SP_SearchTables @Tablenames = 'T2' 
                         ,@SearchStr  = '%TEST%' 

        The above sample searches in tables T1 & T2 with string containing TEST. 

    3. To search in a all table 

        EXEC SP_SearchTables @Tablenames = '%' 
                         ,@SearchStr  = '%TEST%' 

        The above sample searches in all table with string containing TEST. 

    4. Generate the SQL for the Select statements 

        EXEC SP_SearchTables @Tablenames        = 'T1' 
                         ,@SearchStr        = '%TEST%' 
                         ,@GenerateSQLOnly    = 1 

    5. To Search in tables with specfic name 

        EXEC SP_SearchTables @Tablenames        = '%T1%' 
                         ,@SearchStr        = '%TEST%' 
                         ,@GenerateSQLOnly    = 0 

    6. To Search in multiple tables with specfic names 

        EXEC SP_SearchTables @Tablenames        = '%T1%,Dim%' 
                         ,@SearchStr        = '%TEST%' 
                         ,@GenerateSQLOnly    = 0 

    7. To specify multiple search strings 

        EXEC SP_SearchTables @Tablenames        = '%T1%,Dim%' 
                         ,@SearchStr        = '%TEST%,TEST1%,%TEST2' 
                         ,@GenerateSQLOnly    = 0 


    8. To search comma itself in the tables use double comma ",," 

        EXEC SP_SearchTables @Tablenames        = '%T1%,Dim%' 
                         ,@SearchStr        = '%,,%' 
                         ,@GenerateSQLOnly    = 0 

        EXEC SP_SearchTables @Tablenames        = '%T1%,Dim%' 
                         ,@SearchStr        = '%with,,comma%' 
                         ,@GenerateSQLOnly    = 0 

    9. To Search by SchemaName 

        EXEC SP_SearchTables @Tablenames        = '%T1%,Dim%' 
                             ,@SearchStr        = '%,,%' 
                             ,@GenerateSQLOnly    = 0 
                             ,@SchemaNames        = '%dbo%,Sales%' 

*/ 

    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(@Tablenames)) IN ('' ,'%') 
    BEGIN 

        INSERT INTO @CheckTableNames 
        SELECT Name 
          FROM sys.tables 
    END 
    ELSE 
    BEGIN 

        IF CHARINDEX(',',@Tablenames) > 0  
            SELECT @SQL = 'SELECT ''' + REPLACE(@Tablenames,',','''as TblName UNION SELECT ''') + '''' 
        ELSE 
            SELECT @SQL = 'SELECT ''' + @Tablenames + ''' as TblName ' 

        SELECT @TblSQL = 'SELECT T.NAME 
                            FROM SYS.TABLES T 
                            JOIN (' + @SQL + ') tblsrc 
                             ON T.name LIKE tblsrc.tblname ' 




        INSERT INTO @CheckTableNames 
        EXEC(@TblSQL) 

    END 
    */ 

    --IF LTRIM(RTRIM(@Tablenames)) = '' 
    --BEGIN 

    --    SELECT @Tablenames = '%' 
    --END 

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

        SELECT @SchemaNames = '%' 
    END 

    --IF CHARINDEX(',',@Tablenames) > 0  
    --    SELECT @TableParamSQL = 'SELECT ''' + REPLACE(@Tablenames,',','''as TblName UNION SELECT ''') + '''' 
    --ELSE 
    --    SELECT @TableParamSQL = 'SELECT ''' + @Tablenames + ''' as TblName ' 

    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 <> 'SearchTMP' 
      GROUP BY ST.object_id, QUOTENAME(SCh.name) + '.' +  QUOTENAME(ST.NAME) ; 


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



      DELETE FROM @SQLTbl 
       WHERE WHEREClause IS NULL 

    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('SearchTMP','U') IS NOT NULL 
                DROP TABLE SearchTMP 

            EXEC (@SQL) 

            IF EXISTS(SELECT 1 FROM SearchTMP) 
            BEGIN 
                SELECT Tablename=@tmpTblname,* FROM SearchTMP 
                SELECT @MatchFound = 1 
            END 

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

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

    END 

    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 

Sorry in advance with the weird formatting, I can't put it more readable. I hope it helps someone. I also want to give credit to the onwer of the original stored procedure in here.

marc_s
  • 732,580
  • 175
  • 1,330
  • 1,459
Aires Menezes
  • 85
  • 1
  • 15
  • "... to Search for a string in all tables of SQL Server Database ..." how are you going to specify the column in which to search? – Dido Nov 09 '17 at 11:05
  • 3
    Do you really need Enums_Tables? In MSSQL server, for a particular DB, you can always get the table names like this `SELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_TYPE = 'BASE TABLE' AND TABLE_CATALOG='dbName'` – Dido Nov 09 '17 at 11:07
  • unfortunately I need the Enum_Tables, this is mandatory. The thing is, Enum_Tables has an column id, and that column id has the name of several table names of the database. I was hoping that i could use that information to fill the field @Tablenames with that. – Aires Menezes Nov 09 '17 at 11:23

1 Answers1

0

That stored procedure you linked to already has logic to check the table names in the database and populates a table variable with a list of tables to check. Just change this logic to Select from your ENUM_TABLES table instead. This could be based on an input parameter of @Id if you like...

In simple terms:

  1. Remove the parameter @TableNames from the stored procedure
  2. (optionally) replace the parameter with @ENUM_TABLE_ID or something
  3. Change code in SP that looks like this:

    IF LTRIM(RTRIM(@Tablenames)) = '' /* Removed a load of lines looking at @TableNames...... */ .... SELECT @TblSQL = 'SELECT SCh.NAME,T.NAME FROM SYS.TABLES T JOIN SYS.SCHEMAS SCh ON SCh.SCHEMA_ID = T.SCHEMA_ID JOIN (' + @TableParamSQL + ') tblsrc ON T.name LIKE tblsrc.tblname JOIN (' + @SchemaParamSQL + ') schemasrc ON SCh.name LIKE schemasrc.SchemaName

With something more like this:

SELECT @TblSQL = 'SELECT SCh.NAME,T.NAME 
                  FROM SYS.TABLES T 
                  JOIN SYS.SCHEMAS SCh 
                  ON SCh.SCHEMA_ID = T.SCHEMA_ID 
                  INNER JOIN ENUM_TABLES et on 
                     (et.TABLENAME=T.NAME)
                     and (et.Id='+@ENUM_TABLE_ID+')'

And then I think it'll do what you want (lookup the list of tables from another table, based on an ID passed into the stored procedure)

(apologies for the slightly weird formatting of the SQL above; for some reason the SO markdown processor really didn't like that stuff, but it is hopefully readable. If anyone wants to try to edit this to improve it, be my guest.)

GPW
  • 2,528
  • 1
  • 10
  • 22
  • Thank you for answering so quickly, I haven answered sooner, because I was testing your solution. I found some problems, like the collation but i solve it by using COLLATE Latin1_General_CI_AS . I will marked your answer has accepted and I will edit my question with the modifications you game me. Thank you soo much for helping me. – Aires Menezes Nov 09 '17 at 15:11