Search a value to complete database

  • You have no idea how many times in the six months I've been at this job that I've wished for a script like this. Thank you so much!

    ron

    -----
    a haiku...

    NULL is not zero
    NULL is not an empty string
    NULL is the unknown

  • This is great. There have definitely been times in the past that this would come in handy, and I'm sure I'll use it again in the future. It took around 20 minutes to run, but that easily beats out sifting through several tables I'm not familiar with. 🙂

  • Geesh...you guys beat me to it!

    if exists

    (

    select OBJECT_NAME(o.id) as tempdbname, * from tempdb.dbo.sysobjects o

    where o.xtype in ('U')

    and o.id = object_id(N'tempdb..#Table_Name')

    )

    DROP TABLE #Table_Name;

    if exists

    (

    select OBJECT_NAME(o.id) as tempdbname, * from tempdb.dbo.sysobjects o

    where o.xtype in ('U')

    and o.id = object_id(N'tempdb..#SearchTestResult')

    )

    DROP TABLE #SearchTestResult;

    if exists

    (

    select OBJECT_NAME(o.id) as tempdbname, * from tempdb.dbo.sysobjects o

    where o.xtype in ('U')

    and o.id = object_id(N'tempdb..#SearchResult')

    )

    DROP TABLE #SearchResult;

  • Below one is more efficient and gives more info as well ... I have used it many times and its a life saver

    Credit goes to -- Luis Chiriff

    /*

    - Search through tables to find specific text

    - Written by Luis Chiriff (with help from SQL Server Central)

    - luis.chiriff@gmail.com @ 24/11/2008 @ 11:54

    */

    -- Variable Declaration

    Declare @StringToFind VARCHAR(200), @Schema sysname, @Table sysname, @FullTable int, @NewMinID int, @NewMaxID int,

    @SQLCommand VARCHAR(8000), @BaseSQLCommand varchar(8000), @Where VARCHAR(8000), @CountCheck varchar(8000) , @FieldTypes varchar(8000),

    @cursor VARCHAR(8000), @columnName sysname, @SCn int, @SCm int

    Declare @TableList table (Id int identity(1,1) not null, tablename varchar(250))

    Declare @SQLCmds table (id int identity(1,1) not null, sqlcmd varchar(8000))

    Declare @DataFoundInTables table (id int identity(1,1) not null, sqlcmd varchar(8000))

    -- Settings

    SET @StringToFind = 'territory'

    SET NOCOUNT ON

    SET @StringToFind = '%'+@StringToFind+'%'

    -- Gathering Info

    if ((select count(*) from sysobjects where name = 'tempcount') > 0)

    drop table tempcount

    create table tempcount (rowsfound int)

    insert into tempcount select 0

    -- This section here is to accomodate the user defined datatypes, if they have

    -- a SQL Collation then they are assumed to have text in them.

    SET @FieldTypes = ''

    select @FieldTypes = @FieldTypes + '''' + rtrim(ltrim(name))+''',' from systypes where collation is not null or xtype = 36

    select @FieldTypes = left(@FieldTypes,(len(@FieldTypes)-1))

    insert into @TableList (tablename)

    select name from sysobjects

    where xtype = 'U' and name not like 'dtproperties'

    order by name

    -- Start Processing Table List

    select @NewMinID = min(id), @NewMaxID = max(id) from @TableList

    while(@NewMinID <= @NewMaxID)

    Begin

    SELECT @Table = tablename, @Schema='dbo', @Where = '' from @TableList where id = @NewMinID

    SET @SQLCommand = 'SELECT * FROM ' + @Table + ' WHERE'

    -- removed ' + @Schema + '.

    SET @cursor = 'DECLARE col_cursor CURSOR FOR SELECT COLUMN_NAME

    FROM [' + DB_NAME() + '].INFORMATION_SCHEMA.COLUMNS

    WHERE TABLE_SCHEMA = ''' + @Schema + '''

    AND TABLE_NAME = ''' + @Table + '''

    AND DATA_TYPE IN ('+@FieldTypes+')'

    --Original Check, however the above implements user defined data types --AND DATA_TYPE IN (''char'',''nchar'',''ntext'',''nvarchar'',''text'',''varchar'')'

    EXEC (@cursor)

    SET @FullTable = 0

    DELETE FROM @SQLCmds

    OPEN col_cursor

    FETCH NEXT FROM col_cursor INTO @columnName

    WHILE @@FETCH_STATUS = 0

    BEGIN

    SET @Where = @Where + ' [' + @columnName + '] LIKE ''' + @StringToFind + ''''

    SET @Where = @Where + ' OR'

    --PRINT @Table + '|'+ cast(len(isnull(@Where,''))+len(isnull(@SQLCommand,'')) as varchar(10))+'|'+@Where

    if (len(isnull(@Where,''))+len(isnull(@SQLCommand,'')) > 3600)

    Begin

    SELECT @Where = substring(@Where,1,len(@Where)-3)

    insert into @SQLCmds (sqlcmd) select @Where

    SET @Where = ''

    End

    FETCH NEXT FROM col_cursor INTO @columnName

    END

    CLOSE col_cursor

    DEALLOCATE col_cursor

    if (@Where <> '')

    Begin

    SELECT @Where = substring(@Where,1,len(@Where)-3)

    insert into @SQLCmds (sqlcmd)

    select @Where --select @Table,count(*) from @SQLCmds

    End

    SET @BaseSQLCommand = @SQLCommand

    select @SCn = min(id), @SCm = max(id) from @SQLCmds

    while(@SCn <= @SCm)

    Begin

    select @Where = sqlcmd from @SQLCmds where ID = @SCn

    if (@Where <> '')

    Begin

    SET @SQLCommand = @BaseSQLCommand + @Where

    SELECT @CountCheck = 'update tempcount set rowsfound = (select count(*) '+ substring(@SQLCommand,10,len(@SQLCommand)) + ')'

    EXEC (@CountCheck)

    if ((select rowsfound from tempcount) > 0)

    Begin

    PRINT '--- ['+cast(@NewMinID as varchar(15))+'/'+cast(@NewMaxID as varchar(15))+'] '+@Table + ' ----------------------------------[FOUND!]'

    --PRINT '--- [FOUND USING:] ' +@SQLCommand

    insert into @DataFoundInTables (sqlcmd) select @SQLCommand

    EXEC (@SQLCommand)

    update tempcount set rowsfound = 0

    End

    else

    Begin

    PRINT '--- ['+cast(@NewMinID as varchar(15))+'/'+cast(@NewMaxID as varchar(15))+'] '+@Table

    End

    End

    SET @SCn = @SCn + 1

    End

    set @NewMinID = @NewMinID + 1

    end

    if ((select count(*) from sysobjects where name = 'tempcount') > 0)

    drop table tempcount

    /*

    This will now return all the sql commands you need to use

    */

    select @NewMinID = min(id), @NewMaxID = max(id) from @DataFoundInTables

    if (@NewMaxID > 0)

    Begin

    PRINT ' '

    PRINT ' '

    PRINT '-----------------------------------------'

    PRINT '----------- TABLES WITH DATA ------------'

    PRINT '-----------------------------------------'

    PRINT ' '

    PRINT 'We found ' + cast(@NewMaxID as varchar(10)) + ' table(s) with the string '+@StringToFind

    PRINT ' '

    while(@NewMinID <= @NewMaxID)

    Begin

    select @SQLCommand = sqlcmd from @DataFoundInTables where ID = @NewMinID

    PRINT @SQLCommand

    SET @NewMinID = @NewMinID + 1

    End

    PRINT ' '

    PRINT '-----------------------------------------'

    End

    ______________________________________________________________________________________________________________________________________________________________________________________
    HTH !
    Kin
    MCTS : 2005, 2008
    Active SQL Server Community Contributor 🙂

  • SQLQuest29

    that is prety neat script. i am adding that to my tool box.

    note to other users - send result to text - (CTRL +t)

    thanks!

  • Just adding my solution,

    I've been using this one for several years now.

    CREATE PROCEDURE [dbo].[Dev_FindString](@S nvarchar(50))

    AS

    BEGIN

    /*

    Search through colums for specified text (@S)

    Written: Louis Hillebrand

    Louis@LHBsystems.nl

    */

    SET NOCOUNT ON

    DECLARE@Id int = 1,

    @Cnt int,

    @SQL nvarchar(4000),

    @ParmDefinition nvarchar(100) = '@S nvarchar(50), @Cnt int OUTPUT';

    DECLARE @USR_FIND TABLE ([Id] int identity(1,1), [Schema] sysname, [Table] sysname, [Column] sysname, [Count] int);

    INSERT @USR_FIND ([Schema], [Table], [Column], [Count])

    SELECTA.TABLE_SCHEMA,

    A.TABLE_NAME,

    A.COLUMN_NAME,

    0

    FROMINFORMATION_SCHEMA.Columns A INNER JOIN

    INFORMATION_SCHEMA.Tables B ON A.TABLE_NAME = B.TABLE_NAME

    WHEREB.TABLE_TYPE = 'BASE TABLE' AND NOT B.Table_Name LIKE '%MSMERGE%'

    ANDA.Data_Type IN( 'nvarchar' , 'nchar', 'nchar', 'char');

    SELECT * FROM INFORMATION_SCHEMA.COLUMNS

    WHILE EXISTS(SELECT 1 FROM @USR_FIND WHERE Id = @Id)

    BEGIN;

    SELECT@SQL = 'SELECT @Cnt = COUNT(*) FROM [' + [Schema] + '].[' + [Table] + '] WHERE [' + [Column] + '] LIKE @s-2 '

    FROM@USR_Find WHERE Id = @Id

    EXEC sp_ExecuteSQL @SQL, @ParmDefinition, @s-2 = @s-2, @Cnt = @Cnt OUTPUT;

    IF @Cnt > 0

    UPDATE @USR_FIND

    SETCount = @Cnt

    WHEREId = @Id

    SET@Id +=1

    END;

    SELECT [Schema], [Table], [Column], [Count] FROM @USR_FIND WHERE Count > 0 ORDER BY 1, 2, 3;

    END

    GO

    EXEC Dev_FindString 'Louis'

  • I guess if I am learning about a new database that I have been given to support and am searching like this in a development environment, I can see how this would help.

    I think I would have to kill anyone that did such a thing in our production database.

    If I understand, this will run an open-ended LIKE on every table (edit: on every column of every table?)

    Depending on the table... YIKES.

  • scott mcnitt (3/14/2013)


    I guess if I am learning about a new database that I have been given to support and am searching like this in a development environment, I can see how this would help.

    I think I would have to kill anyone that did such a thing in our production database.

    If I understand, this will run an open-ended LIKE on every table (edit: on every column of every table?)

    Depending on the table... YIKES.

    Agreed with you to some extent. There are couple of situations where this would be a life saver and running in PROD makes sense as well ...

    a. Imagine a situation where the front end application is crashing because of "bad data" inserted by user using -- copy paste or the sql provider does not translate it properly and thereby inserting "garbage" into database.

    b. There might be a situation, after cross RDBMS migration like Sybase/Oracle to SQL Server and after the migration there might be data truncation or some other problem with the data.

    You would argue that these must be tested in UAT/QC/DEV, etc ,but trust me ... mistakes/disasters do happen and this will be a life saver ... 😀

    ______________________________________________________________________________________________________________________________________________________________________________________
    HTH !
    Kin
    MCTS : 2005, 2008
    Active SQL Server Community Contributor 🙂

  • Quest, I get it and do not want to seem like my tone is negative here.

    I can only hope that I am never asked to "find some bad data that looks something like

    *this* somewhere in our prod database." Nobody knows the schema. Nobody can answer mapping questions.

    I bet Nobody will complain when the application becomes unusable for 20 minutes with timeouts and they find out that it was a search I was doing.

    I like all the input with variations. They are all good tools to have in your belt.

  • I would add a criteria to only search the columns that could conceivably contain the data. There's no use searching numeric columns for character data, and if you are looking for 5 characters, there's no need to search any character type columns that are shorter.

    I did something like this looking for all occurrences of bad currency codes, and ignored all of the columns that were less than 3 characters wide or were numebric, boolean, datetime, etc. I also used count(*) to give me a summary of how many rows were affected, something like:

    set @sql = 'select ''' +@tn + ''', ''' + @cn + ''', count(*) from ' + @TN + ' where '

    + @cn + ' like ''%xxxx%'' having count(*) <> 0'

    where @TN and @cn are generated by this cursor query:

    declare tc cursor for

    select b.table_name, a.column_name from information_schema.columns a

    join information_schema.tables b

    on a.table_name = b.table_name

    where ((a.data_type = 'varchar' or a.data_type = 'char')and a.character_maximum_length > 2)

    and b.table_type = 'base table'

    order by b.table_name, a.ordinal_position

  • OMG- Tinkered with this and have it pulling where defined variable indicates a social security number.

    Basically replacing the data string with '[0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9][0-9][0-9]'

    I working on another change to find all tables, the db I am looking at uses wack out owner id.

    Thanks!!!!!

    BTW- we are building utility for security to run this periodically after selecting db and defining variable

  • I forgot to add to my earlier post that adding an order by table name and ordinal position in the information_schema select that drives the cursor made a huge difference in performance. For my data, the time to check the entire database went from 8 minutes to under 1.

  • I don't understand why a script to scan across all tables in a database would be needed. Generally speaking, we know ahead of time if we're looking for a customer phone number, order number, etc. In a database with a normalized design and proper naming conventions, it should be obvious where to look.

    Should we find ourselves in the unfortunate position of being handed a database of 200 tables with names like 'MSGCATDEFN' or 'C9', then it may be easier and more rewarding to just polish up the resume and move on to another job.

    "Do not seek to follow in the footsteps of the wise. Instead, seek what they sought." - Matsuo Basho

  • In addition to the earlier suggestions made, I played around with searching other data types as well:

    Declare @keytosearch varchar(max), @numtosearch varchar(max), @datetosearch varchar(25), @Database_Selected varchar(50)

    set @keytosearch = null

    set @numtosearch = '25.00'

    set @datetosearch = '1967-01-20'

    Then I duplicated the IF block for each data type. For numerical data types:

    if @numtosearch is not null and @data_type is not null and (@data_type like '%int%' or @data_type='single'

    or @data_type='double' or @data_type = 'decimal' or @data_type = 'money' or @data_type = 'numeric'

    or @data_type = 'float')

    begin

    set @Result=null

    if @column like '%-%' begin set @Result =('SELECT ''' + @column +''' FROM ' + @Table

    +' Where ''' + @column + ''' = '+@numtosearch+'') end

    else

    set @Result =('SELECT ' + @column +' FROM ' + @Table +' Where ' + @column + ' = '+@numtosearch+'')

    insert into #SearchTestResult exec(@Result)

    set @ID=0

    set @ID=(Select ID from #SearchTestResult where ID=Scope_identity())

    if @ID is not null

    begin

    set @ID_inserted=(select top 1 ID from #SearchResult order by ID desc)

    if @ID_inserted = @ID

    begin

    print ''

    end

    else

    insert into #SearchResult values (@Table,@column)

    end

    end

    and for dates:

    if @datetosearch is not null and @data_type is not null and (@data_type like '%date%')

    begin

    set @Result=null

    if @column like '%-%' begin set @Result =('SELECT ''' + @column +''' FROM ' + @Table

    +' Where ''' + @column + ''' = '''+@datetosearch+'''') end

    else

    set @Result =('SELECT ' + @column +' FROM ' + @Table +' Where ' + @column + ' = '''+@datetosearch+'''')

    insert into #SearchTestResult exec(@Result)

    set @ID=0

    set @ID=(Select ID from #SearchTestResult where ID=Scope_identity())

    if @ID is not null

    begin

    set @ID_inserted=(select top 1 ID from #SearchResult order by ID desc)

    if @ID_inserted = @ID

    begin

    print ''

    end

    else

    insert into #SearchResult values (@Table,@column)

    end

    end

    I also changed the varchar check to also look for char and nchar types by using @data_type like '%char' in the IF predicate.

  • Eric M Russell (3/16/2013)


    I don't understand why a script to scan across all tables in a database would be needed. Generally speaking, we know ahead of time if we're looking for a customer phone number, order number, etc. In a database with a normalized design and proper naming conventions, it should be obvious where to look.

    In a perfect world, that would be true. Unfortunately, many of us work with systems that are rewrites of rebuilds of something that was converted from a mainframe hierarchical design 15 years ago.

    In my case, I came up with this to identify all the tables and fields that contained currency codes that were not ISO compliant, for instance using US$ instead of the ISO standard USD. This was driven by development of an interface to external parties that require ISO standard codes. It's not the sort of thing you would normally use often.

    As far as polishing a resume, after 12 years with the company, and 3 years from earning full retirement with medical, I am not likely to change jobs just because I've been given something difficult to do.

Viewing 15 posts - 16 through 30 (of 31 total)

You must be logged in to reply to this topic. Login to reply