Find a value anywhere in a database

前端 未结 18 882
小蘑菇
小蘑菇 2020-11-22 03:52

Given a #, how do I discover in what table and column it could be found within?

I don\'t care if it\'s fast, it just needs to work.

相关标签:
18条回答
  • 2020-11-22 04:08

    You might need to build an inverted index for your database. It is assured to be pretty fast.

    0 讨论(0)
  • 2020-11-22 04:09

    Here, very sweet and small solution:

    1) create a store procedure:
    
    create procedure get_table
    @find_str varchar(50)
    as 
    begin
      declare @col_name varchar(500), @tab_name varchar(500);
      declare @find_tab TABLE(table_name varchar(100), column_name varchar(100));
    
      DECLARE tab_col cursor for 
      select C.name as 'col_name', T.name as tab_name
      from sys.tables as T
      left outer join sys.columns as C on  C.object_id=T.object_id
      left outer join sys.types as TP on  C.system_type_id=TP.system_type_id
      where type='U' 
      and TP.name in('text','ntext','varchar','char','nvarchar','nchar');
    
      open tab_col
      fetch next from tab_col into @col_name, @tab_name
    
      while @@FETCH_STATUS = 0
      begin        
        insert into @find_tab 
        exec('select ''' +  @tab_name + ''',''' + @col_name + ''' from ' + @tab_name + 
        ' where ' + @col_name + '=''' + @find_str + ''' group by ' + 
        @col_name + ' having count(*)>0');
    
        fetch next from tab_col into @col_name, @tab_name;
      end
      CLOSE tab_col;  
      DEALLOCATE tab_col; 
      select table_name, column_name from @find_tab;
    
    end
    

    ==========================

    2) call procedure by calling store procedure:
    exec get_table 'serach_string';
    
    0 讨论(0)
  • 2020-11-22 04:09

    I was looking for a just a numeric value = 6.84 - using the other answers here I was able to limit my search to this

    Declare @sourceTable Table(id INT NOT NULL IDENTITY PRIMARY KEY, table_name varchar(1000), column_name varchar(1000))
    Declare @resultsTable Table(id INT NOT NULL IDENTITY PRIMARY KEY, table_name varchar(1000))
    
    Insert into @sourceTable(table_name, column_name)
    select schema_name(t.schema_id) + '.' + t.name as[table], c.name as column_name
    from sys.columns c
    join sys.tables t
    on t.object_id = c.object_id
    where type_name(user_type_id) in ('decimal', 'numeric', 'smallmoney', 'money', 'float', 'real')
    order by[table], c.column_id;
    
    DECLARE db_cursor CURSOR FOR
    Select table_name, column_name from @sourceTable
    DECLARE @mytablename VARCHAR(1000);
    DECLARE @mycolumnname VARCHAR(1000);
    
    OPEN db_cursor;
    FETCH NEXT FROM db_cursor INTO @mytablename, @mycolumnname
    
    WHILE @ @FETCH_STATUS = 0
    BEGIN
        Insert into @ResultsTable(table_name)
        EXEC('SELECT ''' + @mytablename + '.' + @mycolumnname + '''  FROM ' + @mytablename + ' (NOLOCK) ' +
        ' WHERE ' + @mycolumnname + '=6.84')
        FETCH NEXT FROM db_cursor INTO @mytablename, @mycolumnname  
    END;
    CLOSE db_cursor;
    DEALLOCATE db_cursor;
    Select Distinct(table_name) from @ResultsTable
    
    0 讨论(0)
  • 2020-11-22 04:17

    Another way using JOIN and CURSOR:

    USE My_Database;
    
    -- Store results in a local temp table so that.  I'm using a
    -- local temp table so that I can access it in SP_EXECUTESQL.
    create table #tmp (
        tbl nvarchar(max),
        col nvarchar(max),
        val nvarchar(max)   
    );
    
    declare @tbl nvarchar(max);
    declare @col nvarchar(max);
    declare @q nvarchar(max);
    declare @search nvarchar(max) = 'my search key';
    
    -- Create a cursor on all columns in the database
    declare c cursor for
    SELECT tbls.TABLE_NAME, cols.COLUMN_NAME  FROM INFORMATION_SCHEMA.TABLES AS tbls
    JOIN INFORMATION_SCHEMA.COLUMNS AS cols
    ON tbls.TABLE_NAME = cols.TABLE_NAME
    
    -- For each table and column pair, see if the search value exists.
    open c
    fetch next from c into @tbl, @col
    while @@FETCH_STATUS = 0
    begin
        -- Look for the search key in current table column and if found add it to the results.
        SET @q = 'INSERT INTO #tmp SELECT ''' + @tbl + ''', ''' + @col + ''', ' + @col + ' FROM ' + @tbl + ' WHERE ' + @col + ' LIKE ''%' + @search + '%'''
        EXEC SP_EXECUTESQL @q
        fetch next from c into @tbl, @col
    end
    close c
    deallocate c
    
    -- Get results
    select * from #tmp
    
    -- Remove local temp table.
    drop table #tmp
    
    0 讨论(0)
  • 2020-11-22 04:18

    This is my independent take on this question that I use for my own work. It works in SQL2000 and greater, allows wildcards, column filtering, and will search most of the normal data types.

    A pseudo-code description could be select * from * where any like 'foo'

    --------------------------------------------------------------------------------
    -- Search all columns in all tables in a database for a string.
    -- Does not search: image, sql_variant or user-defined types.
    -- Exact search always for money and smallmoney; no wildcards for matching these.
    --------------------------------------------------------------------------------
    declare @SearchTerm nvarchar(4000) -- Can be max for SQL2005+
    declare @ColumnName sysname
    
    --------------------------------------------------------------------------------
    -- SET THESE!
    --------------------------------------------------------------------------------
    set @SearchTerm = N'foo' -- Term to be searched for, wildcards okay
    set @ColumnName = N'' -- Use to restrict the search to certain columns, wildcards okay, null or empty string for all cols
    --------------------------------------------------------------------------------
    -- END SET
    --------------------------------------------------------------------------------
    
    set nocount on
    
    declare @TabCols table (
          id int not null primary key identity
        , table_schema sysname not null
        , table_name sysname not null
        , column_name sysname not null
        , data_type sysname not null
    )
    insert into @TabCols (table_schema, table_name, column_name, data_type)
        select t.TABLE_SCHEMA, c.TABLE_NAME, c.COLUMN_NAME, c.DATA_TYPE
        from INFORMATION_SCHEMA.TABLES t
            join INFORMATION_SCHEMA.COLUMNS c on t.TABLE_SCHEMA = c.TABLE_SCHEMA
                and t.TABLE_NAME = c.TABLE_NAME
        where 1 = 1
            and t.TABLE_TYPE = 'base table'
            and c.DATA_TYPE not in ('image', 'sql_variant')
            and c.COLUMN_NAME like case when len(@ColumnName) > 0 then @ColumnName else '%' end
        order by c.TABLE_NAME, c.ORDINAL_POSITION
    
    declare
          @table_schema sysname
        , @table_name sysname
        , @column_name sysname
        , @data_type sysname
        , @exists nvarchar(4000) -- Can be max for SQL2005+
        , @sql nvarchar(4000) -- Can be max for SQL2005+
        , @where nvarchar(4000) -- Can be max for SQL2005+
        , @run nvarchar(4000) -- Can be max for SQL2005+
    
    while exists (select null from @TabCols) begin
    
        select top 1
              @table_schema = table_schema
            , @table_name = table_name
            , @exists = 'select null from [' + table_schema + '].[' + table_name + '] where 1 = 0'
            , @sql = 'select ''' + '[' + table_schema + '].[' + table_name + ']' + ''' as TABLE_NAME, * from [' + table_schema + '].[' + table_name + '] where 1 = 0'
            , @where = ''
        from @TabCols
        order by id
    
        while exists (select null from @TabCols where table_schema = @table_schema and table_name = @table_name) begin
    
            select top 1
                  @column_name = column_name
                , @data_type = data_type
            from @TabCols
            where table_schema = @table_schema
                and table_name = @table_name
            order by id
    
            -- Special case for money
            if @data_type in ('money', 'smallmoney') begin
                if isnumeric(@SearchTerm) = 1 begin
                    set @where = @where + ' or [' + @column_name + '] = cast(''' + @SearchTerm + ''' as ' + @data_type + ')' -- could also cast the column as varchar for wildcards
                end
            end
            -- Special case for xml
            else if @data_type = 'xml' begin
                set @where = @where + ' or cast([' + @column_name + '] as nvarchar(max)) like ''' + @SearchTerm + ''''
            end
            -- Special case for date
            else if @data_type in ('date', 'datetime', 'datetime2', 'datetimeoffset', 'smalldatetime', 'time') begin
                set @where = @where + ' or convert(nvarchar(50), [' + @column_name + '], 121) like ''' + @SearchTerm + ''''
            end
            -- Search all other types
            else begin
                set @where = @where + ' or [' + @column_name + '] like ''' + @SearchTerm + ''''
            end
    
            delete from @TabCols where table_schema = @table_schema and table_name = @table_name and column_name = @column_name
    
        end
    
        set @run = 'if exists(' + @exists + @where + ') begin ' + @sql + @where + ' print ''' + @table_name + ''' end'
        print @run
        exec sp_executesql @run
    
    end
    
    set nocount off
    

    I don't put it in proc form since I don't want to maintain it across hundreds of DBs and it's really for ad-hoc work anyway. Please feel free to comment on bug-fixes.

    0 讨论(0)
  • 2020-11-22 04:23

    Thanks for the really useful script.

    You may need to add the following modification to the code if your tables have non-convertable fields:

    SET @ColumnName =
        (
            SELECT MIN(QUOTENAME(COLUMN_NAME))
            FROM    INFORMATION_SCHEMA.COLUMNS
            WHERE       TABLE_SCHEMA    = PARSENAME(@TableName, 2)
                AND TABLE_NAME  = PARSENAME(@TableName, 1)
                AND DATA_TYPE NOT IN ('text', 'image', 'ntext')                 
                AND QUOTENAME(COLUMN_NAME) > @ColumnName
        )
    

    Chris

    0 讨论(0)
提交回复
热议问题