Search All Tables In All Databases On Server For A String
Solution 1:
First, you have to collect list of all databases' names from sys.databases.
Then you have to create dynamic SQL to extract names of all tables in all databases in format like [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'
When you get all of that, you can create dynamic queries to all your tables and text columns.
BTW If somebody hide data inside of TEXT column you have to include it in your search and do a conversion.
Solution 2:
Edited :
My answer was a stored procedure . here the query for you :
Change @SearchTerm for your search.
declare@SearchTerm nvarchar(12)
set@SearchTerm='WORD'CREATETABLE #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 databasesAND[state] =0-- onlineAND user_access =0; -- multi-userSET@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
ORDERBY[database],[schema],[table],[column];
Solution 3:
Assuming this is a one time thing here is an alternative to the cursor approach. This will build a dynamic string that you can then execute. It does NOT work for every database but you could either run this for each database manually or modify this to use sp_msforeachdb. You may find that this approach is better though since the undocumented foreachdb will sometimes miss databases. https://sqlblog.org/2010/12/29/a-more-reliable-and-more-flexible-sp_msforeachdb
DECLARE@MySearchCriteriaVARCHAR(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 ISNOTNULLAND c.max_length >6and t2.name notin ('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 ISNOTNULLAND c.max_length >6and t2.name notin ('text', 'ntext')
FOR XML PATH('')
), 1, 4, '' )
) w (whereclause)
where c.columnlist isnotnullORDERBY t.name
Solution 4:
I don't know if this would help, it's vb.net code I wrote, it finds the table and field a string is in, potentially searching all DB's - it's just an investigation aid, I've added field types as they've cropped up, but it might give you an idea how I did it anyway
Private Sub Button1_Click(sender As System.Object, e As System.EventArgs) Handles Button1.Click
Dim scon AsString = String.Format("Data Source={0};Initial Catalog=MASTER;Integrated Security=True", cmbInstance.SelectedItem.ToString)
Button1.Enabled = False
Dim Matches AsNewList(Of Locator)
With ListVresults
.Clear()
.View = View.Details
.Columns.Add("Database", 200)
.Columns.Add("Table", 200)
.Columns.Add("Field", 200)
End With
Using con AsNew SqlConnection(scon),
da AsNew SqlDataAdapter("select *, SCHEMA_NAME(schema_id ) as SkeemaName from sys.tables where type = 'U'", con),
daDB AsNew SqlDataAdapter("select * from sys.databases WHERE name NOT IN ('master', 'tempdb', 'model', 'msdb') and state = 0 ORDER BY NAME", con),
dtDB AsNew DataTable
Dim UseLike AsBoolean = chkLIKE.Checked
Dim CompOperator AsString = 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 AsBoolean = 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 AsString = 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 AsNew DataTable,
daDat AsNew 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)
IfString.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 AsNew 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
Solution 5:
This is the script I always use... set the string to search for at the top (see comment) and let it run.
DECLARE@tableName sysname
DECLARE@columnName sysname
DECLARE@valuevarchar(100)
DECLARE@sqlvarchar(2000)
DECLARE@sqlPreamblevarchar(100)
DECLARE@minLengthint;
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 FORSELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLES
WHERE TABLE_SCHEMA ='dbo'AND TABLE_TYPE ='BASE TABLE'AND TABLE_NAME !='dtproperties'AND TABLE_NAME !='sysdiagrams'ORDERBY TABLE_NAME
OPEN theTableCursor
FETCH NEXT FROM theTableCursor INTO@tableName
WHILE @@FETCH_STATUS =0-- spin through Table entriesBEGINDECLARE theColumnCursor CURSOR FAST_FORWARD FORSELECT COLUMN_NAME FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_NAME =@tableNameAND (DATA_TYPE ='nvarchar'OR DATA_TYPE ='varchar')
AND (CHARACTER_MAXIMUM_LENGTH >=@minlengthOR CHARACTER_MAXIMUM_LENGTH =-1)
ORDERBY ORDINAL_POSITION
OPEN theColumnCursor
FETCH NEXT FROM theColumnCursor INTO@columnName
WHILE @@FETCH_STATUS =0-- spin through Column entriesBEGINSET@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@columnNameENDCLOSE theColumnCursor
DEALLOCATE theColumnCursor
FETCH NEXT FROM theTableCursor INTO@tableNameENDCLOSE theTableCursor
DEALLOCATE theTableCursor
Post a Comment for "Search All Tables In All Databases On Server For A String"