【问题标题】:Search all tables in all databases on server for a string在服务器上的所有数据库中的所有表中搜索字符串
【发布时间】:2016-12-14 10:15:30
【问题描述】:

编辑:这个问题被标记为重复,但事实并非如此。 SO上的其他答案显示了如何搜索单个数据库中的所有表,我需要搜索给定服务器上每个数据库中的所有表。

我需要在服务器上的所有数据库的所有表中搜索搜索字符串。我的电子邮件地址散落在要更改域的表格中,我需要准备一份报告,显示这些电子邮件地址的位置。我将无法向所有数据库添加存储过程,因此我需要一个查询来执行此操作,这不涉及重复执行 sp。我从the net 中提取了这段代码,并使用它来搜索所有表,但我无法弄清楚如何在所有数据库上运行它。

drop table #Results
CREATE TABLE #Results (ColumnName nvarchar(370), ColumnValue nvarchar(3630))

SET NOCOUNT ON

DECLARE @SearchStr nvarchar(100), @TableName nvarchar(256), @ColumnName nvarchar(128), @SearchStr2 nvarchar(110)
SET @SearchStr = '@domaintobereplaced.com'
SET  @TableName = ''
SET @SearchStr2 = QUOTENAME('%' + @SearchStr + '%','''')

WHILE @TableName IS NOT NULL
BEGIN
    SET @ColumnName = ''
    SET @TableName = 
    (
        SELECT MIN(QUOTENAME(TABLE_SCHEMA) + '.' + QUOTENAME(TABLE_NAME))
        FROM    INFORMATION_SCHEMA.TABLES
        WHERE       TABLE_TYPE = 'BASE TABLE'
            AND QUOTENAME(TABLE_SCHEMA) + '.' + QUOTENAME(TABLE_NAME) > @TableName
            AND OBJECTPROPERTY(
                    OBJECT_ID(
                        QUOTENAME(TABLE_SCHEMA) + '.' + QUOTENAME(TABLE_NAME)
                         ), 'IsMSShipped'
                           ) = 0
    )

    WHILE (@TableName IS NOT NULL) AND (@ColumnName IS NOT NULL)
    BEGIN
        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 IN ('char', 'varchar', 'nchar', 'nvarchar')
                AND QUOTENAME(COLUMN_NAME) > @ColumnName
        )

        IF @ColumnName IS NOT NULL
        BEGIN
            INSERT INTO #Results
            EXEC
            (
                'SELECT top 10 ''' + @TableName + '.' + @ColumnName + ''', LEFT(' + @ColumnName + ', 3630) 
                FROM ' + @TableName + ' (NOLOCK) ' +
                ' WHERE ' + @ColumnName + ' LIKE ' + @SearchStr2
            )
        END
    END 
END

SELECT ColumnName, ColumnValue FROM #Results

【问题讨论】:

  • 你在服务器上安装了 phpmyadmin 吗?
  • 在你的sql server找到sp_MSforeachdb直接使用或者查看它的代码。
  • 我有sql server management studio,不是php myadmin
  • 在所有数据库上运行,通过查询 sys.databases 获取它们并使用游标,但是您可以在字段上执行 USE 吗?或者您是否必须将数据库名称构建到动态 SQL 中 - 不确定。
  • 我当然希望这是一次性调查的事情。如果您必须定期运行此程序,则会出现严重错误。无论您如何切片,这都不会很快。您要求 sql server 在整个服务器上的单个数据库中的每个表的每一列或每一行中查找特定值。根据系统的不同,这可能每次都需要数小时才能运行。

标签: sql sql-server tsql search


【解决方案1】:

假设这是一次性的,这是光标方法的替代方法。这将构建一个动态字符串,然后您可以执行该字符串。它不适用于每个数据库,但您可以手动为每个数据库运行它或修改它以使用 sp_msforeachdb。您可能会发现这种方法更好,因为未记录的 foreachdb 有时会丢失数据库。 https://sqlblog.org/2010/12/29/a-more-reliable-and-more-flexible-sp_msforeachdb

DECLARE @MySearchCriteria VARCHAR(500)
SET @MySearchCriteria = '''YourSearchStringHere''' --you do need all these quotation marks because this string is injected to another string.

SELECT 'SELECT ''' + t.name + ''' as TableName, ' + c.columnlist + '] FROM [' + s.name + '].[' + t.name + '] WHERE ' + w.whereclause  as SelectStatement
FROM sys.tables t 
join sys.schemas s on s.schema_id = t.schema_id
CROSS APPLY (
    SELECT STUFF((    
        SELECT '], [' + c.Name AS [text()]
        FROM sys.columns c
        join sys.types t2 on t2.user_type_id = c.user_type_id
        WHERE t.object_id = c.object_id 
            AND c.collation_name IS NOT NULL
            AND c.max_length > 6
            and t2.name not in ('text', 'ntext')
        FOR XML PATH('') 
    ), 1, 2, '' )
) c (columnlist)
CROSS APPLY (
    SELECT STUFF((    
        SELECT ' OR [' + c.Name + '] IN (' + @MySearchCriteria + ')' AS [text()]
        FROM sys.columns c
        join sys.types t2 on t2.user_type_id = c.user_type_id
        WHERE t.object_id = c.object_id 
            AND c.collation_name IS NOT NULL
            AND c.max_length > 6
            and t2.name not in ('text', 'ntext')
        FOR XML PATH('') 
    ), 1, 4, '' )
) w (whereclause)
where c.columnlist is not null
ORDER BY t.name

【讨论】:

    【解决方案2】:

    这个问题在这一点上有点老了,大多数答案似乎在搜索每台服务器上的所有服务器和所有数据库方面都没有达到目标。原来我的经理只是想给我一个不可能完成且耗时的任务,也就是忙碌的工作来拖延我的时间,因为我们的团队正在重组中解散,我们都被派往公司的不同部门。

    所以,为了写出一个全面的答案,我会说我现在的方法是创建一个控制台应用程序,它接受以逗号分隔的服务器名称列表。它将遍历所有服务器名称并一一连接到它们。一旦进入服务器,我将查询并遍历所有用户创建的数据库,并对每个数据库运行搜索所有表查询。如果找到结果,我会将它们写入存储在具有 [ServerName]_[DatabaseName]_Results 标题的目录中的文件中,然后使用输出的文件列表来审查和制定行动计划以进行进一步的查询/修复。从上面的答案看来,SQL Server 没有办法做到这一点。

    【讨论】:

      【解决方案3】:

      已编辑:

      我的答案是存储过程。 这里为您查询:

      为您的搜索更改@SearchTerm。

      declare @SearchTerm nvarchar(12)
      set @SearchTerm = 'WORD'
      CREATE TABLE #results
        (
          [database]   SYSNAME,
          [schema]     SYSNAME,
          [table]      SYSNAME,
          [column]     SYSNAME,
          ExampleValue NVARCHAR(1000)
        );
      
        DECLARE
          @DatabaseCommands  NVARCHAR(MAX) = N'', 
          @ColumnCommands NVARCHAR(MAX) = N'';
      
        SELECT @DatabaseCommands = @DatabaseCommands + N'
          EXEC ' + QUOTENAME(name) + '.sys.sp_executesql
              @ColumnCommands, N''@SearchTerm NVARCHAR(MAX)'', @SearchTerm;'
          FROM sys.databases
          WHERE database_id  > 4  -- non-system databases
            AND[state]      = 0-- online
            AND user_access  = 0; -- multi-user
      
          SET @ColumnCommands = N'DECLARE @q NCHAR(1),
                @SearchCommands NVARCHAR(MAX);
      
      SELECT @q = NCHAR(39),
        @SearchCommands = N''DECLARE @VSearchTerm VARCHAR(255) = @SearchTerm;'';
      
          SELECT @SearchCommands = @SearchCommands + CHAR(10) + N''
      
            SELECT TOP(1)
              [db]     = DB_NAME(),
              [schema] = N'' + @q + s.name + @q + '', 
              [table]  = N'' + @q + t.name + @q + '',
              [column] = N'' + @q + c.name + @q + '',
              ExampleValue = LEFT('' + QUOTENAME(c.name) + '', 1000)
            FROM '' + QUOTENAME(s.name) + ''.'' + QUOTENAME(t.name) + ''
            WHERE '' + QUOTENAME(c.name) + N'' LIKE @'' + CASE
              WHEN c.system_type_id IN(35, 167, 175) THEN ''V'' 
              ELSE '''' END + ''SearchTerm;'' 
      
          FROM sys.schemas AS s
          INNER JOIN sys.tables AS t
          ON s.[schema_id] = t.[schema_id]
          INNER JOIN sys.columns AS c
          ON t.[object_id] = c.[object_id]
          WHERE c.system_type_id IN (35, 99, 167, 175, 231, 239)
            AND c.max_length >= LEN(@SearchTerm);
      
      PRINT @SearchCommands;
      EXEC sys.sp_executesql @SearchCommands,
        N''@SearchTerm NVARCHAR(255)'', @SearchTerm;';
      
        INSERT #Results
        (
          [database],
          [schema],
          [table],
          [column],
          ExampleValue
        )
        EXEC[master].sys.sp_executesql @DatabaseCommands,
         N'@ColumnCommands NVARCHAR(MAX), @SearchTerm NVARCHAR(255)', 
          @ColumnCommands, @SearchTerm;
      
        SELECT[Searched for] = @SearchTerm;
      
        SELECT[database],[schema],[table],[column],ExampleValue
      FROM #Results 
          ORDER BY[database],[schema],[table],[column];
      

      【讨论】:

        【解决方案4】:

        这是我一直使用的脚本...将要搜索的字符串设置在顶部(见评论)并让它运行。

        DECLARE @tableName sysname
        DECLARE @columnName sysname
        DECLARE @value varchar(100)
        DECLARE @sql varchar(2000)
        DECLARE @sqlPreamble varchar(100)
        DECLARE @minLength int;
        
        SET @value = '%SomeString%' -- *** Set this to the value you're searching for *** --
        SET @minLength = LEN(REPLACE(@value, '%', ''));
        
        SET @sqlPreamble = 'IF EXISTS (SELECT 1 FROM '
        
        DECLARE theTableCursor CURSOR FAST_FORWARD FOR 
            SELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLES
             WHERE TABLE_SCHEMA = 'dbo' AND TABLE_TYPE = 'BASE TABLE' 
               AND TABLE_NAME != 'dtproperties' AND TABLE_NAME != 'sysdiagrams'
             ORDER BY TABLE_NAME
        
        OPEN theTableCursor
        FETCH NEXT FROM theTableCursor INTO @tableName
        
        WHILE @@FETCH_STATUS = 0 -- spin through Table entries
        BEGIN
            DECLARE theColumnCursor CURSOR FAST_FORWARD FOR 
                SELECT COLUMN_NAME FROM INFORMATION_SCHEMA.COLUMNS
                 WHERE TABLE_NAME = @tableName 
                   AND (DATA_TYPE = 'nvarchar' OR DATA_TYPE = 'varchar')
                   AND (CHARACTER_MAXIMUM_LENGTH >= @minlength OR CHARACTER_MAXIMUM_LENGTH = -1)
                 ORDER BY ORDINAL_POSITION
        
            OPEN theColumnCursor
            FETCH NEXT FROM theColumnCursor INTO @columnName
        
            WHILE @@FETCH_STATUS = 0 -- spin through Column entries
            BEGIN
                SET @sql = N'[' + @tableName + N'] (nolock) WHERE [' + @columnName + N'] LIKE ''' + @value + 
                           N''') PRINT ''Value found in Table: ' + @tableName + N', Column: ' +  @columnName + N''''
                EXEC (@sqlPreamble + @sql)
                FETCH NEXT FROM theColumnCursor INTO @columnName
            END
            CLOSE theColumnCursor
            DEALLOCATE theColumnCursor
        
            FETCH NEXT FROM theTableCursor INTO @tableName
        END
        CLOSE theTableCursor
        DEALLOCATE theTableCursor
        

        【讨论】:

          【解决方案5】:

          我不知道这是否有帮助,这是我编写的 vb.net 代码,它找到了字符串所在的表和字段,可能会搜索所有数据库 - 这只是一个调查辅助工具,我已将字段类型添加为他们已经出现了,但它可能会让你知道我是怎么做到的

              Private Sub Button1_Click(sender As System.Object, e As System.EventArgs) Handles Button1.Click
          
              Dim scon As String = String.Format("Data Source={0};Initial Catalog=MASTER;Integrated Security=True", cmbInstance.SelectedItem.ToString)
          
              Button1.Enabled = False
              Dim Matches As New List(Of Locator)
          
              With ListVresults
          
                  .Clear()
          
                  .View = View.Details
          
          
                  .Columns.Add("Database", 200)
                  .Columns.Add("Table", 200)
                  .Columns.Add("Field", 200)
          
              End With
          
          
              Using con As New SqlConnection(scon),
                      da As New SqlDataAdapter("select *, SCHEMA_NAME(schema_id )  as SkeemaName from sys.tables where type = 'U'", con),
                      daDB As New SqlDataAdapter("select * from sys.databases WHERE name NOT IN ('master', 'tempdb', 'model', 'msdb') and state = 0 ORDER BY NAME", con),
                      dtDB As New DataTable
          
                  Dim UseLike As Boolean = chkLIKE.Checked
                  Dim CompOperator As String = If(chkLIKE.Checked, "LIKE", "=")
          
                  con.Open()
          
          
                  daDB.Fill(dtDB)
          
                  For Each drdb As DataRow In dtDB.Select(If(cmbDB.SelectedIndex = 0, "", String.Format("name = '{0}'", cmbDB.SelectedItem.ToString)), "name")
                      'For Each drdb As DataRow In dtDB.Rows
          
                      con.ChangeDatabase(drdb!name.ToString)
          
                      Using dt As New DataTable
                          da.Fill(dt)
                          For Each dr As DataRow In dt.Select("", "name")
                              lblProc.Text = String.Format("({2} - {0} - {1}", drdb!name.ToString, dr!name.ToString, Matches.Count)
                              Application.DoEvents()
                              Dim sql As New System.Text.StringBuilder
                              Using dsDatNull As New DataSet,
                                  daDatNull As New SqlDataAdapter(String.Format("SELECT * FROM [{0}].[{1}] WHERE 1=0; SELECT * FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_SCHEMA = '{0}' AND TABLE_NAME = '{1}'", dr!skeemaName, dr!name), con)
          
                                  daDatNull.Fill(dsDatNull)
          
                                  'SELECT * FROM(INFORMATION_SCHEMA.COLUMNS) WHERE TABLE_NAME = 'absence'
          
                                  sql.AppendFormat("SELECT * FROM [{0}].[{1}] WHERE ", dr!skeemaname, dr!name)
          
          
          
                                  Dim bOR As Boolean = False
          
                                  Dim col As DataColumn
                                  Dim Q As System.Data.EnumerableRowCollection(Of System.Data.DataRow) = (From x As DataRow In dsDatNull.Tables(1) Where String.Compare(x!column_name.ToString, col.ColumnName, True) = 0 Select x)
          
                                  For Each col In dsDatNull.Tables(0).Columns
          
                                      Dim drColType As DataRow = Q(0)
                                      Dim dataType As String = drColType!Data_Type.ToString
          
          
                                      If "x".GetType Is col.DataType AndAlso (String.Compare(dataType, "nvarchar", True) = 0 _
                                                                                  OrElse String.Compare(dataType, "varchar", True) = 0 _
                                                                                  OrElse String.Compare(dataType, "nchar", True) = 0 _
                                                                                  OrElse String.Compare(dataType, "char", True) = 0) Then
          
          
          
                                          If bOR Then sql.Append(" OR ")
                                          bOR = True
                                          sql.Append("[" + col.ColumnName + "]").Append(If(UseLike, " LIKE ", " = ")).AppendFormat("'{0}{1}{2}'", If(UseLike, "%", ""), txtCode.Text.Replace("'", "''"), If(UseLike, "%", ""))
          
          
                                      ElseIf (New Guid).GetType Is col.DataType Then
          
                                          If bOR Then sql.Append(" OR ")
                                          bOR = True
                                          sql.Append("cast([" + col.ColumnName + "] as nvarchar(80))").Append(If(UseLike, " LIKE ", " = ")).AppendFormat("'{0}{1}{2}'", If(UseLike, "%", ""), txtCode.Text.Replace("'", "''"), If(UseLike, "%", ""))
          
          
                                      End If
          
                                  Next
          
                                  If Not bOR Then sql.Append(" 1=0 ")
          
                              End Using
          
          
          
                              Using dtDat As New DataTable,
                                  daDat As New SqlDataAdapter(sql.ToString, con)
                                  daDat.SelectCommand.CommandTimeout = 3600
          
                                  daDat.Fill(dtDat)
          
                                  For Each drDat As DataRow In dtDat.Rows
                                      For Each col As DataColumn In dtDat.Columns
          
                                          Dim obj = drDat(col)
          
                                          If String.Compare(obj.ToString, txtCode.Text, True) = 0 OrElse UseLike And obj.ToString.ToLower.Contains(txtCode.Text.ToLower) Then
          
                                              If Not (From x As Locator In Matches Where x.DB.ToString = drdb!name.ToString And x.Table = dr!name.ToString And x.Column = col.ColumnName).Any Then
                                                  Dim newOne As New Locator(drdb!name.ToString, dr!name.ToString, col.ToString)
                                                  Matches.Add(newOne)
                                                  With newOne
                                                      ListVresults.Items.Add(New ListViewItem({.DB, .Table, .Column}))
                                                  End With
          
                                              End If
                                          End If
          
                                      Next
                                  Next
          
          
                              End Using
          
          
                          Next
                      End Using
          
                  Next
              End Using
          
              lblProc.Text = ""
          
          
              Button1.Enabled = True
          End Sub
          

          【讨论】:

            【解决方案6】:

            首先,您必须从sys.databases 收集所有数据库名称的列表。
            然后,您必须创建动态 SQL 以提取所有数据库中所有表的名称,格式为 [database].[schema].[table name]'. You can do it by linking following tables:[database].sys.schemas' & [database].sys.tables'<BR/> Then you get list of all text columns by linking found tables to[database].sys.columns'
            完成所有这些后,您就可以为所有表格和文本列创建动态查询。

            顺便说一句,如果有人将数据隐藏在 TEXT 列中,您必须将其包含在搜索中并进行转换。

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2011-11-23
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              相关资源
              最近更新 更多