web-dev-qa-db-fra.com

Comment trouver une chaîne dans une base de données entière?

J'ai une chaîne spécifique, telle que "123abcd" par exemple, mais je ne connais pas le nom de la table ni même le nom de la colonne à l'intérieur de la table de ma base de données SQL Server. Je veux le trouver avec une sélection et afficher toutes les colonnes de la chaîne associée, alors je me demandais quelque chose comme:

select * from Database.dbo.* where * like  '%123abcd%'

Pour des raisons évidentes, cela ne fonctionne pas, mais il existe un moyen simple de créer une instruction select pour faire quelque chose comme ça?

44
Diogo

Cela fonctionnera:

DECLARE @MyValue NVarChar(4000) = 'something';

SELECT S.name SchemaName, T.name TableName
INTO #T
FROM sys.schemas S INNER JOIN
     sys.tables T ON S.schema_id = T.schema_id;

WHILE (EXISTS (SELECT * FROM #T)) BEGIN
  DECLARE @SQL NVarChar(4000) = 'SELECT * FROM $$TableName WHERE (0 = 1) ';
  DECLARE @TableName NVarChar(1000) = (
    SELECT TOP 1 SchemaName + '.' + TableName FROM #T
  );
  SELECT @SQL = REPLACE(@SQL, '$$TableName', @TableName);

  DECLARE @Cols NVarChar(4000) = '';

  SELECT
    @Cols = COALESCE(@Cols + 'OR CONVERT(NVarChar(4000), ', '') + C.name + ') = CONVERT(NVarChar(4000), ''$$MyValue'') '
  FROM sys.columns C
  WHERE C.object_id = OBJECT_ID(@TableName);

  SELECT @Cols = REPLACE(@Cols, '$$MyValue', @MyValue);
  SELECT @SQL = @SQL + @Cols;

  EXECUTE(@SQL);

  DELETE FROM #T
  WHERE SchemaName + '.' + TableName = @TableName;
END;

DROP TABLE #T;

Quelques mises en garde, cependant. Tout d’abord, c’est scandaleusement lent et non optimisé . Toutes les valeurs sont converties en nvarchar simplement pour pouvoir être comparées sans erreur. Vous pouvez rencontrer des problèmes avec des valeurs telles que datetime qui ne sont pas converties comme prévu et qui ne correspondent donc pas quand elles devraient l'être (faux négatifs).

La WHERE (0 = 1) est là pour faciliter la construction de la clause OR. S'il n'y a pas de correspondance, vous n'obtiendrez aucune ligne.

28
Yuck

Voici quelques autres outils gratuits pouvant être utilisés pour cela. Les deux fonctionnent comme addins SSMS.

ApexSQL Search - 100% gratuit - recherche à la fois le schéma et les données dans des tables. A quelques options plus utiles telles que le suivi des dépendances…

Le pack d’outils SSMS - est gratuit pour toutes les versions, à l’exception de SQL 2012, n’a pas l’air aussi avancé que la version précédente, mais il possède de nombreuses autres fonctionnalités intéressantes. 

11
John Moore
create procedure usp_find_string(@string as varchar(1000))
as
begin
declare @mincounter as int
declare @maxcounter as int
declare @stmtquery as varchar(1000)
set @stmtquery=''
create table #tmp(tablename varchar(128),columnname varchar(128),rowid int identity)
create table #tablelist(tablename varchar(128),columnname varchar(128))
declare @tmp table(name varchar(128))
declare @tablename as varchar(128)
declare @columnname as varchar(128)

insert into #tmp(tablename,columnname)
select a.name,b.name as columnname from sysobjects a
inner join syscolumns b on a.name=object_name(b.id)
where a.type='u'
and b.xtype in(select xtype from systypes
    where name='text' or name='ntext' or name='varchar' or name='nvarchar' or name='char' or name='nchar')
order by a.name

select @maxcounter=max(rowid),@mincounter=min(rowid) from #tmp 
while(@mincounter <= @maxcounter )
begin
 select @tablename=tablename, @columnname=columnname from #tmp where rowid=@mincounter
 set @stmtquery ='select top 1  ' + '[' +@columnname+']' + ' from ' + '['+@tablename+']' + ' where ' + '['+@columnname+']' + ' like ' + '''%' + @string + '%'''
 insert into @tmp(name) exec(@stmtquery)
 if @@rowcount >0
 insert into #tablelist values(@tablename,@columnname)
 set @mincounter=@mincounter +1
end
select * from #tablelist
end
4

Je pense que vous avez des options:

  1. Construisez un SQL dynamique en utilisant sys.tables et sys.columns pour effectuer la recherche ( exemple ici ).

  2. Utilisez n'importe quel programme ayant cette fonction. Un exemple de ceci est SQL Workbench (free).

4
DavidEG

Dans Oracle, vous pouvez utiliser la commande SQL suivante pour générer les commandes SQL dont vous avez besoin:

select 
     "select * "
     " from "||table_name||
     " where "||column_name||" like '%123abcd%' ;" as sql_command
from user_tab_columns
where data_type='VARCHAR2';
3
Raihan

SQL Locator (gratuit) a très bien fonctionné pour moi. Il vient avec beaucoup d'options et il est assez facile à utiliser.

2
Gabe

Common Resource Grep (crgrep) recherche les correspondances de chaînes dans les tables/colonnes par nom ou contenu et prend en charge un certain nombre de bases de données, notamment SQLServer, Oracle et autres. Wild-carding complet et autres options utiles.

C'est opensource (je suis l'auteur). 

http://sourceforge.net/projects/crgrep/

2
Craig

J'utilise habituellement information_Schema.columns et information_schema.tables, bien que, comme @yuck ait dit, sys.tables et sys.columns soient plus courts à taper.

Dans une boucle, concaténez ces

@sql = @sql + 'select' + column_name + 
' from ' + table_name + 
' where ' + column_name ' like ''%''+value+''%' UNION

Ensuite, exécutez le SQL résultant. 

2
MatthewMartin

Désolé pour la réponse tardive, mais je venais aussi de poser cette question et j'ai fini par la résoudre en utilisant une autre approche qui est probablement plus générique pour toutes les bases de données. 

  1. créer un vidage de la base de données. 
  2. À partir de là, vous devriez pouvoir ouvrir le fichier dans un éditeur de texte et rechercher la chaîne requise.
2
meowcat

Voici une solution facile et pratique à base de curseur

DECLARE
@search_string  VARCHAR(100),
@table_name     SYSNAME,
@table_id       INT,
@column_name    SYSNAME,
@sql_string     VARCHAR(2000)

SET @search_string = 'StringtoSearch'

DECLARE tables_cur CURSOR FOR SELECT name, object_id FROM sys.objects WHERE  type = 'U'

OPEN tables_cur

FETCH NEXT FROM tables_cur INTO @table_name, @table_id

WHILE (@@FETCH_STATUS = 0)
BEGIN
    DECLARE columns_cur CURSOR FOR SELECT name FROM sys.columns WHERE object_id = @table_id 
        AND system_type_id IN (167, 175, 231, 239)

    OPEN columns_cur

    FETCH NEXT FROM columns_cur INTO @column_name
        WHILE (@@FETCH_STATUS = 0)
        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 NEXT FROM columns_cur INTO @column_name
        END

    CLOSE columns_cur

DEALLOCATE columns_cur

FETCH NEXT FROM tables_cur INTO @table_name, @table_id
END

CLOSE tables_cur
DEALLOCATE tables_cur
0
Noor A Shuvo