编辑:此问题被标记为重复,但事实并非如此。 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
答案 0 :(得分:1)
首先,您必须从sys.databases
收集所有数据库名称的列表。
然后,您必须创建动态SQL,以[database].[schema].[table name]'. You can do it by linking following tables:
[数据库] .sys.schemas'和&amp ;; [database].sys.tables'<BR/>
Then you get list of all text columns by linking found tables to
[数据库] .sys.columns'
获得所有这些后,您可以为所有表和文本列创建动态查询。
BTW如果有人隐藏TEXT
列中的数据,您必须将其包含在搜索中并进行转换。
答案 1 :(得分:1)
编辑:
我的回答是存储过程。 这里是你的查询:
更改@ 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];
答案 2 :(得分:0)
我不知道这是否会有所帮助,我写的是vb.net代码,它找到了一个字符串所在的表和字段,可能会搜索所有数据库 - 它&#39 ;只是一个调查助手,我已经添加了字段类型,但它可能会让你知道我是怎么做的
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
答案 3 :(得分:0)
假设这是一次性的事情,这是游标方法的替代方案。这将构建一个动态字符串,然后您可以执行该字符串。它不适用于每个数据库,但您可以手动为每个数据库运行此操作,也可以将其修改为使用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
答案 4 :(得分:0)
这是我一直使用的脚本...设置要在顶部搜索的字符串(请参阅注释)并让它运行。
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 :(得分:0)
此问题在这一点上有点陈旧,大多数答案似乎都错过了在每台服务器上搜索所有服务器和所有数据库的标记。事实证明,我的经理只是试图给我一个不可能和耗时的任务,也就是忙于工作以阻止我,因为我们的团队在重组中解散了,我们都被送到了公司的不同部门。
因此,为了编写一个全面的答案,我将说我现在的方法是创建一个接受逗号分隔的服务器名称列表的控制台应用程序。它将循环遍历所有服务器名称并逐个连接到它们。一旦进入服务器,我将查询并遍历所有用户创建的数据库,并在每个数据库上运行搜索所有表查询。如果找到结果,我会将它们写入存储在具有[ServerName] _ [DatabaseName] _Results标题的目录中的文件,然后使用输出的文件列表来查看和开发以及进一步查询/修复的行动计划。从上面的答案中可以看出,在SQL Server中有一种方法可以做到这一点。