20

I have a database where a misspelled string appears in various places in different tables. Is there a SQL query that I can use to search for this string in every possible varchar/text column in the database?

I was thinking of trying to use the information_schema views somehow to create dynamic queries, but I'm not sure if that will work, or if there's a better way.

I'm using MS SQL Server if that helps.

Andy White
  • 86,444
  • 48
  • 176
  • 211

7 Answers7

26

Using the technique found here the following script generates SELECT's for all ((n)var)char columns in the given database. Copy/paste the output, remove the very last 'union' and execute.. You'll need to replace MISSPELLING HERE with the string you're looking for.

select 
'select distinct ''' + tab.name + '.' + col.name 
+ '''  from [' + tab.name 
+ '] where [' + col.name + '] like ''%MISSPELLING HERE%'' union ' 
from sys.tables tab 
join sys.columns col on (tab.object_id = col.object_id)
join sys.types types on (col.system_type_id = types.system_type_id) 
where tab.type_desc ='USER_TABLE' 
and types.name IN ('CHAR', 'NCHAR', 'VARCHAR', 'NVARCHAR');
Community
  • 1
  • 1
edosoft
  • 17,121
  • 25
  • 77
  • 111
  • +1 Nice short answer, thanks for looking into it. I'll wait and see if either gets upvoted more before selecting one – Andy White May 07 '09 at 15:03
  • 2
    +1 Maybe add (NOLOCK) or "set transaction isolation level read uncommitted" if you plan to run this on a production database – Andomar May 07 '09 at 15:46
  • what would adding NOLOCK accomplish? I would think sys.objects isn't updated that often. – edosoft Apr 22 '10 at 13:25
  • After running this and then running the results, I get: Msg 102, Level 15, State 1, Line 138 Incorrect syntax near 'union'. – Levitikon May 27 '12 at 14:08
7

Using queries for this will make this more complex than really needed. Why not consider some of the free SQL Search tools that exist out there. ApexSQL has ApexSQL Search, and there is also SQL Search from Red-Gate. Both of these will get the job done easily.

Mark Davidson
  • 414
  • 6
  • 4
4

You could use a cursor and the sys.tables/sys.columns views to go through them. Give me a minute, and I'll give you the code.

Update: Here you are:

declare @col_name nvarchar(50)
declare @sql nvarchar(max)
declare @tbl_name nvarchar(50)
declare @old_str nvarchar(50)
declare @new_str nvarchar(50)

set @old_str = 'stakoverflow'
set @new_str = 'StackOverflow'

declare fetch_name cursor for
select 
    c.name,
    t.name
from 
    sys.columns c
    inner join sys.tables t on c.object_id = t.object_id
    inner join sys.types y on c.system_type_id = y.system_type_id
where
    y.name like '%varchar'
    or y.name like '%text'

open fetch_name

fetch next from fetch_name into @col_name, @tbl_name

while @@fetch_status = 0
begin
    set @sql = 'UPDATE ' + @tbl_name + ' SET ' + 
        @col_name + ' = replace(' + 
            @col_name + ',''' + 
            @old_str + ''',''' + 
            @new_str + ''')'

    exec sp_executesql @sql

    fetch next from fetch_name into @col_name
end

close fetch_name
deallocate fetch_name

This will get you everything you need. It grabs the columns that are varchar, nvarchar, text, and ntext from your database, cycle through the columns and update each one.

Of course, you could also do this to create a concatenated SQL statement and do one big update at the end, but hey, that's your preference.

And for the record, I don't like cursors, but since we're dealing with a few columns and not millions of rows, I'm okay with this one.

Eric
  • 92,005
  • 12
  • 114
  • 115
  • Nice script. However it seems to me this only updates a single table (called 'MyTable') ? – edosoft May 07 '09 at 14:43
  • +1 Cool, I was working on something that looks just about like this. Both good answers, I'll wait and see if one gets upvoted more than the other to select one. – Andy White May 07 '09 at 15:02
  • Avoid cursors whenever possible! They're evil, they're procedural and don't fit SQL Server well. The other answer is the much better answer because of that fact. – marc_s May 07 '09 at 15:25
  • 2
    marc, did you read my bloody post? Since we're only dealing with a few columns, cursor's are up for this task. The other answers builds a bunch of statements that would have to be copied then run by hand, and in fact, is contained within this script, which is plug-and-play. If you read the post, I acknowledged the danger of cursors when dealing with millions (or even thousands!) of rows of data. Cursors are not _always_ bad, and opinions like that will only keep you from using the most effective tool to do a job. – Eric May 07 '09 at 15:28
  • 1
    I agree, cursors get a bad rap. For something that doesn't need to be performant, who cares. Sometimes it's easier to approach the data in a procedural fashion, rather than trying to handle conditional type logic in where clauses/joins. – Andy White May 07 '09 at 18:08
1

SQL Server 2000 version of the script above (from edosoft):

select  
'select distinct ''[' + tab.name + ']'' as TableName, ''[' + col.name + ']'' as ColumnName'
+ ' from [' + users.name + '].[' + tab.name  
+ '] where UPPER([' + col.name + ']) like ''%MISSPELLING HERE%'' union '  
from sysobjects tab  
join syscolumns col on (tab.id = col.id) 
join systypes types on (col.xtype = types.xtype)  
join sysusers users on (tab.uid = users.uid)
where tab.xtype ='U'  
and types.name IN ('char', 'nchar', 'varchar', 'nvarchar'); 
vtmind
  • 11
  • 1
0

If anyone should require something like this for Sybase, the following could help.

I have created the following script, where the code prints out all TableNames, ColumnNames containing the search string.

Not performance optimised, using a cursor to loop through the DB columns, so it might take a while to run this on a big DB (depending on size, number of tables/cols etc.)

However, I think it's a nice utility to search for a string in a DB.

-----------------------------------------------------------------------------------------------------
-- SYBASE - SCRIPT TO FIND STRING IN ANY COLUMN IN TABLE AND PRINT TableName/ColumnName TO RESULTS --
-----------------------------------------------------------------------------------------------------

-- tested on Sybase ASE 15.7

set nocount off

-- CREATE OBJECTS REQUIRED FOR SCRIPT
create table #SearchString (SearchString varchar(100))
go

-- SET SEARCH STRING
declare @search_string  varchar(100)
set @search_string = 'SEARCH_STRING'

-- WRITE SEARCH STRING TO TEMP TABLE TO STORE IT AWAY AND BE ABLE TO READ IT IN NEXT BATCH
insert into #SearchString (SearchString)
    values (@search_string)

-- GET ALL RELEVANT TABLES AND COLUMNS
insert #TabCol
    select object_name(o.id) as TableName, c.name as ColumnName
        from sysobjects o, syscolumns c 
    where o.type = 'U' -- ONLY USER TABLES
          and c.usertype in (1,2,18,19,24,25,42) -- ONLY LOOK FOR CHAR, VARCHAR, ETC.
          and c.id = o.id
          and c.name is not null
          and c.length >= datalength(@search_string)
go

-- GET TOTAL NUMBER OF RELEVANT COLUMNS
select count(*) as RelevantColumns from #TabCol
go

-- CREATE CURSOR TO LOOP THROUGH TABLES AND COLUMNS TO FIND COLUMNS CONTAINING THE SEARCH STRING
declare cur cursor for 
select TableName, ColumnName from #TabCol order by TableName, ColumnName
for read only
go

-- VARIABLE DEFINITION
declare
    @table_name     SYSNAME,
    @table_id       int,
    @column_name    SYSNAME,
    @sql_string     varchar(2000),
    @search_string  varchar(100)

-- GET SEARCH STRING FROM TABLE
select @search_string = SearchString from #SearchString

-- CURSOR INIT
open cur

fetch cur into @table_name, @column_name

-- LOOP THROUGH TABLES AND COLUMNS SEARCHING FOR SEARCH STRING AND PRINT IF FOUND
while (@@sqlstatus != 2)
begin
    set @sql_string = 'if exists (select * from ' + @table_name + ' where [' + @column_name + '] like ''%' + @search_string + '%'') print ''' + @table_name + ', ' + @column_name + ''''
    execute(@sql_string)
    fetch cur into @table_name, @column_name
end
go

-- CLEAN-UP
close cur
deallocate cur

drop table #SearchString
drop table #TabCol
go

Cheers

Remo
  • 21
  • 6
0

I included the schema to edosoft's version.

select 
'select distinct ''[' +  SCHEMA_NAME(tab.schema_id) + '].[' + tab.name + '].[' + col.name + ']'
+ '''  from [' +  SCHEMA_NAME(tab.schema_id) + '].[' + tab.name 
+ '] where [' + col.name + '] like ''%hsapp%'' union ' 
from sys.tables tab 
join sys.columns col on (tab.object_id = col.object_id)
join sys.types types on (col.system_type_id = types.system_type_id) 
where tab.type_desc ='USER_TABLE' 
and types.name IN ('CHAR', 'NCHAR', 'VARCHAR', 'NVARCHAR');
Karson
  • 449
  • 6
  • 11
-1
select column_name from information_schema.columns 
    where table_name ='magazines' and DATA_TYPE IN ('CHAR', 'NCHAR', 'VARCHAR', 'NVARCHAR');

hope it helps

kleopatra
  • 51,061
  • 28
  • 99
  • 211