2009-05-07 22 views
17

Tengo una base de datos donde una cadena mal escrita aparece en varios lugares en diferentes tablas. ¿Existe una consulta SQL que pueda usar para buscar esta cadena en todas las columnas de varchar/text posibles en la base de datos?SQL: busque una cadena en cada columna varchar en una base de datos

Estaba pensando en intentar usar las vistas de information_schema de alguna manera para crear consultas dinámicas, pero no estoy seguro de si eso funcionará, o si hay una manera mejor.

Estoy usando MS SQL Server si eso ayuda.

Respuesta

22

Usando la técnica encontrada here la siguiente secuencia de comandos genera SELECT para todas las columnas ((n) var) char en la base de datos dada. Copia/pega la salida, elimina la última 'unión' y ejecuta .. Tendrás que reemplazar MISSPELLING HERE con la cadena que estás buscando.

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'); 
+0

+1 Bonita respuesta corta, gracias por mirarla. Voy a esperar y ver si se sube un voto más antes de seleccionar uno –

+2

+1 Quizás agregar (NOLOCK) o "establecer el nivel de aislamiento de transacción leído no confirmado" si planea ejecutar esto en una base de datos de producción – Andomar

+0

¿qué lograría agregar NOLOCK? Creo que sys.objects no se actualiza con tanta frecuencia. – edosoft

4

Puede usar un cursor y las vistas sys.tables/sys.columns para revisarlas. Dame un minuto, y te daré el código.

Actualización: aquí están:

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 

Esto le dará todo lo que necesita. Captura las columnas que son varchar, nvarchar, text y ntext de su base de datos, recorre las columnas y actualiza cada una.

Por supuesto, también puede hacer esto para crear una declaración SQL concatenada y hacer una gran actualización al final, pero bueno, esa es su preferencia.

Y para que conste, no me gustan los cursores, pero como estamos trabajando con unas pocas columnas y no con millones de filas, estoy de acuerdo con esta.

+0

Buena secuencia de comandos. Sin embargo, me parece que esto solo actualiza una sola tabla (llamada 'MyTable')? – edosoft

+0

Muy bien. Editado para que sea dinámico. – Eric

+0

+1 Genial, estaba trabajando en algo que se parece a esto. Ambas buenas respuestas, esperaré y veré si alguien se sube más que el otro para seleccionar uno. –

1

SQL Server versión 2000 de la secuencia de comandos (de 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'); 
-1
select column_name from information_schema.columns 
    where table_name ='magazines' and DATA_TYPE IN ('CHAR', 'NCHAR', 'VARCHAR', 'NVARCHAR'); 

creo que sirve

7

Utilización de consultas para que esto hará que esto más complejo de lo que realmente se necesita. ¿Por qué no considerar algunas de las herramientas gratuitas de búsqueda SQL que existen? ApexSQL tiene ApexSQL Search, y también hay SQL Search de Red-Gate. Ambos harán el trabajo fácilmente.

0

Si alguien necesita algo como esto para Sybase, lo siguiente podría ayudar.

He creado la siguiente secuencia de comandos, donde el código imprime todos los TableNames, ColumnNames que contienen la cadena de búsqueda.

No rendimiento optimizado, usando un cursor para recorrer las columnas de base de datos, lo que podría tomar un tiempo para ejecutar esto en una gran base de datos (dependiendo del tamaño, número de mesas/cols etc.)

Sin embargo, Creo que es una buena utilidad buscar una cadena en un 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 

Saludos

0

que incluyen el esquema para la versión de Edosoft.

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'); 
Cuestiones relacionadas