views:

1323

answers:

4

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.

+4  A: 

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
Nice script. However it seems to me this only updates a single table (called 'MyTable') ?
edosoft
Quite right. Edited it to be dynamic.
Eric
+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
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
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
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
+7  A: 

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');
edosoft
+1 Nice short answer, thanks for looking into it. I'll wait and see if either gets upvoted more before selecting one
Andy White
+1 Maybe add (NOLOCK) or "set transaction isolation level read uncommitted" if you plan to run this on a production database
Andomar
what would adding NOLOCK accomplish? I would think sys.objects isn't updated that often.
edosoft
+1  A: 

the comment the cursors are evil is uninformed. Cursors have their place and actually seems like a good use of a cursor.

Jim S
A: 

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