I created this to help me identify source tables and columns for data in poorly documented or structured databases.
The usage instruction are contained in the comments.
I created this to help me identify source tables and columns for data in poorly documented or structured databases.
The usage instruction are contained in the comments.
/* Name: SearchForString Author: Wes Henriksen What this Script Does: * Iterate through every text based column of every table of every schema in a database * The message tab provides useful progress updates while the script is running * Identifies which columns contain the specified string with a count of rows containing the string * Change the grouping in the last select statement to see the full data. How to Use this Script: 1. Configure search variables, see specific instructions with the variables 2. Run the script. 3. The results are stored in temporary table #Results. You can query this table from within the same session to further refine your results or remove the GROUP BY to see detailed data. WARNING -- READ BEFORE RUNNING THIS SCRIPT! * Since this script can iterate through every table and column of a database, it may take a VERY long time to process. * Run your initial tests on a single table or column to see how your system handles the load. */DECLARE @MaxRows INT; DECLARE @MinRows INT; DECLARE @FilterSchema NVARCHAR(255); DECLARE @FilterTable NVARCHAR(255); DECLARE @FilterColumn NVARCHAR(255); DECLARE @Characters NVARCHAR(MAX); --Filter the tables by a minimum and maximum number of rows, use this to target data tables or lookup tables --a. MinRows = 0 to search all tables, 1 to search any tables containing data. --b. MaxRows = null to search all tables, > 0 to search tables containing fewer rows than this number. SET @MaxRows = 1000; SET @MinRows = 1; --Configure any schema, table or column name filters in the variables section. --Names are compared using Like %Name% SET @FilterSchema = NULL; SET @FilterTable = NULL; SET @Filtercolumn = NULL; --Input the text you want to search for. The search term will be searched as a whole, and will not look for individual occurrences of --multiple words in one search term. SET @Characters = 'Approved' --******Script begins. do not change anything below this point**** --*************************************************************** DECLARE @SchemaT TABLE ( RowID INT IDENTITY(1 , 1), SchemaName NVARCHAR(MAX), TableName NVARCHAR(MAX), ColumnName NVARCHAR(MAX) ) IF OBJECT_ID('tempdb..#Results') IS NOT NULL BEGIN DROP TABLE #Results END CREATE TABLE #Results ( RowID INT IDENTITY(1 , 1), RSchemaName NVARCHAR(MAX) DEFAULT '', RTableName NVARCHAR(MAX) DEFAULT '', RColumnName NVARCHAR(MAX) DEFAULT '', Value NTEXT DEFAULT '' ) DECLARE @LoopNo INT, @TotalRows INT, @Schema NVARCHAR(MAX), @Table NVARCHAR(MAX), @Column NVARCHAR(MAX), @SQL NVARCHAR(MAX), @ParamDef NVARCHAR(MAX), @DataExists BIT DECLARE @ReturnValue NVARCHAR(MAX) DECLARE @ParmDefinition NVARCHAR(MAX) --**************************************************************************************************** --Gather list of columns to search. Schema, table and column name and table size filters are applied --**************************************************************************************************** INSERT INTO @SchemaT ( SchemaName, TableName, ColumnName ) SELECT Sch = t.Sch, Tbl = REPLACE(REPLACE(t.Tbl , '[' , '[[') , ']' , ']]'), Col = c.name FROM ( SELECT s.Name AS Sch, t.name AS Tbl, t.object_id, SUM(p.rows) AS NumCount FROM sys.schemas s LEFT JOIN sys.tables t ON s.schema_id = t.schema_id LEFT JOIN sys.partitions p ON t.object_id = p.object_id LEFT JOIN sys.allocation_units a ON p.partition_id = a.container_id WHERE p.index_id IN ( 0 , 1 ) -- 0 heap table , 1 table with clustered index AND p.rows IS NOT NULL AND a.type = 1 -- row-data only , not LOB AND ( s.name LIKE '%' + @FilterSchema + '%' OR @FilterSchema IS NULL ) AND ( t.name LIKE '%' + @FilterTable + '%' OR @FilterTable IS NULL ) GROUP BY s.Name, t.name, t.object_id HAVING ( SUM(p.rows) >= @MinRows AND ( SUM(p.rows) <= @MaxRows OR @MaxRows IS NULL ) ) ) T INNER JOIN sys.columns C ON T.object_id = c.object_id INNER JOIN sys.types P ON C.system_type_id = p.system_type_id WHERE ( p.name LIKE '%char%' OR p.name LIKE '%text%' ) AND ( c.name LIKE '%' + @FilterColumn + '%' OR @FilterColumn IS NULL ) ORDER BY Sch, Tbl, Col --********************************************************************************** --Build and execute search strings and input the results into #Results --********************************************************************************** SELECT @LoopNo = 1, @TotalRows = MAX(RowID) FROM @SchemaT PRINT 'Total Rows = ' + CAST(@TotalRows AS NCHAR(5)) WHILE @LoopNo <= @TotalRows BEGIN SELECT @Schema = SchemaName, @Table = TableName, @Column = ColumnName FROM @SchemaT WHERE RowID = @LoopNo SET @SQL = 'SELECT [' + @Column + '] FROM [' + @Schema + '].[' + @Table + '] where charINDEX(''' + @Characters + ''',[' + @Column + ']) > 0' --********************************* --Show progress on the message tab --********************************* PRINT @Schema + '.' + @Table + '.' + @Column PRINT @SQL PRINT 'Row ' + CAST(@LoopNo AS NCHAR(5)) + ' @ ' + CAST(CAST(CURRENT_TIMESTAMP AS DATETIME) AS NVARCHAR(12)) --********************************* SET @ParmDefinition = '@ReturnValueOUT NVARCHAR(MAX) OUTPUT' INSERT INTO #Results ( Value ) EXECUTE sp_executesql @SQL, @ParmDefinition, @ReturnValueOUT = @ReturnValue OUTPUT UPDATE #Results SET RTableName = @Table, RColumnName = @Column, RSchemaName = @Schema WHERE RTableName = '' SET @LoopNo = @LoopNo + 1 END --********************************************************************************** --Display the results, aggregated by column. --********************************************************************************** SELECT COUNT(*) AS Occurrences, RSchemaName, RTableName, RColumnName FROM #Results GROUP BY RSchemaName, RTableName, RColumnName