Related
Given a number, 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.
This might help you. - from Narayana Vyas. It searches all columns of all tables in a given database. I have used it before and it works.
This is the Stored Proc from the above link - the only change I made was substituting the temp table for a table variable so you don't have to remember to drop it each time.
CREATE PROC SearchAllTables
(
#SearchStr nvarchar(100)
)
AS
BEGIN
-- Copyright © 2002 Narayana Vyas Kondreddi. All rights reserved.
-- Purpose: To search all columns of all tables for a given search string
-- Written by: Narayana Vyas Kondreddi
-- Site: http://vyaskn.tripod.com
-- Tested on: SQL Server 7.0 and SQL Server 2000
-- Date modified: 28th July 2002 22:50 GMT
DECLARE #Results TABLE(ColumnName nvarchar(370), ColumnValue nvarchar(3630))
SET NOCOUNT ON
DECLARE #TableName nvarchar(256), #ColumnName nvarchar(128), #SearchStr2 nvarchar(110)
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 ''' + #TableName + '.' + #ColumnName + ''', LEFT(' + #ColumnName + ', 3630)
FROM ' + #TableName +
' WHERE ' + #ColumnName + ' LIKE ' + #SearchStr2
)
END
END
END
SELECT ColumnName, ColumnValue FROM #Results
END
To execute the stored procedure :
EXEC SearchAllTables 'YourStringHere'
If you need to run such search only once then you can probably go with any of the scripts already shown in other answers. But otherwise, I’d recommend using ApexSQL Search for this. It’s a free SSMS addin and it really saved me a lot of time.
Before running any of the scripts you should customize it based on the data type you want to search. If you know you are searching for datetime column then there is no need to search through nvarchar columns. This will speed up all of the queries above.
Based on bnkdev's answer I modified Narayana's Code to search all columns even numeric ones.
It'll run slower, but this version actually finds all matches not just those found in text columns.
I can't thank this guy enough. Saved me days of searching by hand!
CREATE PROC SearchAllTables
(
#SearchStr nvarchar(100)
)
AS
BEGIN
-- Copyright © 2002 Narayana Vyas Kondreddi. All rights reserved.
-- Purpose: To search all columns of all tables for a given search string
-- Written by: Narayana Vyas Kondreddi
-- Site: http://vyaskn.tripod.com
-- Tested on: SQL Server 7.0 and SQL Server 2000
-- Date modified: 28th July 2002 22:50 GMT
CREATE TABLE #Results (ColumnName nvarchar(370), ColumnValue nvarchar(3630))
SET NOCOUNT ON
DECLARE #TableName nvarchar(256), #ColumnName nvarchar(128), #SearchStr2 nvarchar(110)
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 QUOTENAME(COLUMN_NAME) > #ColumnName
)
IF #ColumnName IS NOT NULL
BEGIN
INSERT INTO #Results
EXEC
(
'SELECT ''' + #TableName + '.' + #ColumnName + ''', LEFT(CONVERT(varchar(max), ' + #ColumnName + '), 3630)
FROM ' + #TableName + ' (NOLOCK) ' +
' WHERE CONVERT(varchar(max), ' + #ColumnName + ') LIKE ' + #SearchStr2
)
END
END
END
SELECT ColumnName, ColumnValue FROM #Results
END
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.
I optimized Allain Lalonde answer (https://stackoverflow.com/a/436676/412368).
Numeric values are still supported. Should be roughly 4-5 times faster (1:03 vs 4:30), tested on a desktop with a 7GB database. http://developer.azurewebsites.net/2015/01/mssql-searchalltables/
IF OBJECT_ID ('dbo.SearchAllTables', 'P') IS NOT NULL
DROP PROCEDURE dbo.SearchAllTables;
GO
CREATE PROC SearchAllTables
(
#SearchStr nvarchar(100)
)
AS
BEGIN
-- Copyright © 2002 Narayana Vyas Kondreddi. All rights reserved.
-- Purpose: To search all columns of all tables for a given search string
-- Written by: Narayana Vyas Kondreddi
-- Site: http://vyaskn.tripod.com
-- Customized and modified: 2014-01-21
-- Tested on: SQL Server 2008 R2
DECLARE #Results TABLE(ColumnName nvarchar(370), ColumnValue nvarchar(3630))
SET NOCOUNT ON
DECLARE #TableName nvarchar(256)
DECLARE #ColumnName nvarchar(128)
DECLARE #DataType nvarchar(128)
DECLARE #SearchStr2 nvarchar(110)
DECLARE #SearchDecimal decimal(38,19)
DECLARE #Query nvarchar(4000)
SET #SearchStr2 = QUOTENAME('%' + #SearchStr + '%', '''')
SET #SearchDecimal = CASE WHEN ISNUMERIC(#SearchStr) = 1 THEN CONVERT(decimal(38,19), #SearchStr) ELSE NULL END
PRINT '#SearchStr2: ' + #SearchStr2
PRINT '#SearchDecimal: ' + CAST(#SearchDecimal AS nvarchar)
SET #TableName = ''
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))
DATA_TYPE
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_SCHEMA = PARSENAME(#TableName, 2)
AND TABLE_NAME = PARSENAME(#TableName, 1)
AND DATA_TYPE IN ('char', 'varchar', 'nchar', 'nvarchar',
'int', 'bigint', 'tinyint', 'numeric', 'decimal')
AND QUOTENAME(COLUMN_NAME) > #ColumnName
)
SET #DataType =
(
SELECT DATA_TYPE
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_SCHEMA = PARSENAME(#TableName, 2)
AND TABLE_NAME = PARSENAME(#TableName, 1)
AND QUOTENAME(COLUMN_NAME) = #ColumnName
)
PRINT #TableName + '.' + #ColumnName + ' (' + #DataType + ')'
IF #ColumnName IS NOT NULL
BEGIN
IF #DataType IN ('int', 'bigint', 'tinyint', 'numeric', 'decimal')
BEGIN
IF #SearchDecimal IS NOT NULL
BEGIN
SET #Query = 'SELECT ''' + #TableName + '.' + #ColumnName + ''', LEFT(CAST(' + #ColumnName + ' AS nvarchar(110)), 3630) ' +
'FROM ' + #TableName + ' (NOLOCK) ' +
' WHERE ' + #ColumnName + ' = ' + CAST(#SearchDecimal AS nvarchar)
PRINT ' ' + #Query
INSERT INTO #Results
EXEC (#Query)
END
END
ELSE
BEGIN
SET #Query = 'SELECT ''' + #TableName + '.' + #ColumnName + ''', LEFT(' + #ColumnName + ', 3630) ' +
'FROM ' + #TableName + ' (NOLOCK) ' +
' WHERE ' + #ColumnName + ' LIKE ' + #SearchStr2
PRINT ' ' + #Query
INSERT INTO #Results
EXEC (#Query)
END
END
END
END
SELECT ColumnName, ColumnValue FROM #Results
END
I have a solution from a while ago that I kept improving. Also searches within XML columns if told to do so, or searches integer values if providing a integer only string.
/* Reto Egeter, fullparam.wordpress.com */
DECLARE #SearchStrTableName nvarchar(255), #SearchStrColumnName nvarchar(255), #SearchStrColumnValue nvarchar(255), #SearchStrInXML bit, #FullRowResult bit, #FullRowResultRows int
SET #SearchStrColumnValue = '%searchthis%' /* use LIKE syntax */
SET #FullRowResult = 1
SET #FullRowResultRows = 3
SET #SearchStrTableName = NULL /* NULL for all tables, uses LIKE syntax */
SET #SearchStrColumnName = NULL /* NULL for all columns, uses LIKE syntax */
SET #SearchStrInXML = 0 /* Searching XML data may be slow */
IF OBJECT_ID('tempdb..#Results') IS NOT NULL DROP TABLE #Results
CREATE TABLE #Results (TableName nvarchar(128), ColumnName nvarchar(128), ColumnValue nvarchar(max),ColumnType nvarchar(20))
SET NOCOUNT ON
DECLARE #TableName nvarchar(256) = '',#ColumnName nvarchar(128),#ColumnType nvarchar(20), #QuotedSearchStrColumnValue nvarchar(110), #QuotedSearchStrColumnName nvarchar(110)
SET #QuotedSearchStrColumnValue = QUOTENAME(#SearchStrColumnValue,'''')
DECLARE #ColumnNameTable TABLE (COLUMN_NAME nvarchar(128),DATA_TYPE nvarchar(20))
WHILE #TableName IS NOT NULL
BEGIN
SET #TableName =
(
SELECT MIN(QUOTENAME(TABLE_SCHEMA) + '.' + QUOTENAME(TABLE_NAME))
FROM INFORMATION_SCHEMA.TABLES
WHERE TABLE_TYPE = 'BASE TABLE'
AND TABLE_NAME LIKE COALESCE(#SearchStrTableName,TABLE_NAME)
AND QUOTENAME(TABLE_SCHEMA) + '.' + QUOTENAME(TABLE_NAME) > #TableName
AND OBJECTPROPERTY(OBJECT_ID(QUOTENAME(TABLE_SCHEMA) + '.' + QUOTENAME(TABLE_NAME)), 'IsMSShipped') = 0
)
IF #TableName IS NOT NULL
BEGIN
DECLARE #sql VARCHAR(MAX)
SET #sql = 'SELECT QUOTENAME(COLUMN_NAME),DATA_TYPE
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_SCHEMA = PARSENAME(''' + #TableName + ''', 2)
AND TABLE_NAME = PARSENAME(''' + #TableName + ''', 1)
AND DATA_TYPE IN (' + CASE WHEN ISNUMERIC(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(#SearchStrColumnValue,'%',''),'_',''),'[',''),']',''),'-','')) = 1 THEN '''tinyint'',''int'',''smallint'',''bigint'',''numeric'',''decimal'',''smallmoney'',''money'',' ELSE '' END + '''char'',''varchar'',''nchar'',''nvarchar'',''timestamp'',''uniqueidentifier''' + CASE #SearchStrInXML WHEN 1 THEN ',''xml''' ELSE '' END + ')
AND COLUMN_NAME LIKE COALESCE(' + CASE WHEN #SearchStrColumnName IS NULL THEN 'NULL' ELSE '''' + #SearchStrColumnName + '''' END + ',COLUMN_NAME)'
INSERT INTO #ColumnNameTable
EXEC (#sql)
WHILE EXISTS (SELECT TOP 1 COLUMN_NAME FROM #ColumnNameTable)
BEGIN
PRINT #ColumnName
SELECT TOP 1 #ColumnName = COLUMN_NAME,#ColumnType = DATA_TYPE FROM #ColumnNameTable
SET #sql = 'SELECT ''' + #TableName + ''',''' + #ColumnName + ''',' + CASE #ColumnType WHEN 'xml' THEN 'LEFT(CAST(' + #ColumnName + ' AS nvarchar(MAX)), 4096),'''
WHEN 'timestamp' THEN 'master.dbo.fn_varbintohexstr('+ #ColumnName + '),'''
ELSE 'LEFT(' + #ColumnName + ', 4096),''' END + #ColumnType + '''
FROM ' + #TableName + ' (NOLOCK) ' +
' WHERE ' + CASE #ColumnType WHEN 'xml' THEN 'CAST(' + #ColumnName + ' AS nvarchar(MAX))'
WHEN 'timestamp' THEN 'master.dbo.fn_varbintohexstr('+ #ColumnName + ')'
ELSE #ColumnName END + ' LIKE ' + #QuotedSearchStrColumnValue
INSERT INTO #Results
EXEC(#sql)
IF ##ROWCOUNT > 0 IF #FullRowResult = 1
BEGIN
SET #sql = 'SELECT TOP ' + CAST(#FullRowResultRows AS VARCHAR(3)) + ' ''' + #TableName + ''' AS [TableFound],''' + #ColumnName + ''' AS [ColumnFound],''FullRow>'' AS [FullRow>],*' +
' FROM ' + #TableName + ' (NOLOCK) ' +
' WHERE ' + CASE #ColumnType WHEN 'xml' THEN 'CAST(' + #ColumnName + ' AS nvarchar(MAX))'
WHEN 'timestamp' THEN 'master.dbo.fn_varbintohexstr('+ #ColumnName + ')'
ELSE #ColumnName END + ' LIKE ' + #QuotedSearchStrColumnValue
EXEC(#sql)
END
DELETE FROM #ColumnNameTable WHERE COLUMN_NAME = #ColumnName
END
END
END
SET NOCOUNT OFF
SELECT TableName, ColumnName, ColumnValue, ColumnType, COUNT(*) AS Count FROM #Results
GROUP BY TableName, ColumnName, ColumnValue, ColumnType
Source:
http://fullparam.wordpress.com/2012/09/07/fck-it-i-am-going-to-search-all-tables-all-collumns/
It's my way to resolve this question. Tested on SQLServer2008R2
CREATE PROC SearchAllTables
#SearchStr nvarchar(100)
AS
BEGIN
DECLARE #dml nvarchar(max) = N''
IF OBJECT_ID('tempdb.dbo.#Results') IS NOT NULL DROP TABLE dbo.#Results
CREATE TABLE dbo.#Results
([tablename] nvarchar(100),
[ColumnName] nvarchar(100),
[Value] nvarchar(max))
SELECT #dml += ' SELECT ''' + s.name + '.' + t.name + ''' AS [tablename], ''' +
c.name + ''' AS [ColumnName], CAST(' + QUOTENAME(c.name) +
' AS nvarchar(max)) AS [Value] FROM ' + QUOTENAME(s.name) + '.' + QUOTENAME(t.name) +
' (NOLOCK) WHERE CAST(' + QUOTENAME(c.name) + ' AS nvarchar(max)) LIKE ' + '''%' + #SearchStr + '%'''
FROM sys.schemas s JOIN sys.tables t ON s.schema_id = t.schema_id
JOIN sys.columns c ON t.object_id = c.object_id
JOIN sys.types ty ON c.system_type_id = ty.system_type_id AND c .user_type_id = ty .user_type_id
WHERE t.is_ms_shipped = 0 AND ty.name NOT IN ('timestamp', 'image', 'sql_variant')
INSERT dbo.#Results
EXEC sp_executesql #dml
SELECT *
FROM dbo.#Results
END
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
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';
If you have phpMyAdmin installed use its Search feature.
Select your DataBase.
Be sure you do have selected DataBase, not a table, otherwise you'll get a completely different search dialog.
Click Search tab
List item Choose the search term you want
Choose the tables to search
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
You might need to build an inverted index for your database. It is assured to be pretty fast.
-- exec pSearchAllTables 'M54*'
ALTER PROC pSearchAllTables (#SearchStr NVARCHAR(100))
AS
BEGIN
-- A procedure to search all tables in a database for a value
-- Note: Use * or % for wildcard
DECLARE
#Results TABLE([Schema.Table.ColumnName] NVARCHAR(370), ColumnValue NVARCHAR(3630))
SET NOCOUNT ON
DECLARE
#TableName NVARCHAR(256) = ''
, #ColumnName NVARCHAR(128)
, #SearchStr2 NVARCHAR(110) = QUOTENAME(REPLACE(#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 ''' + #TableName + '.' + #ColumnName + ''', LEFT(' + #ColumnName + ', 3630) FROM ' + #TableName + ' (NOLOCK) WHERE ' + #ColumnName + ' LIKE ' + #SearchStr2)
END
END
END
SELECT
[Schema.Table.ColumnName]
, ColumnValue
FROM #Results
GROUP BY
[Schema.Table.ColumnName]
, ColumnValue
END
For Development purpose you can just export the required tables data into a single HTML and make a direct search on it.
Suppose if you want to get all the table with name a column name contain logintime in the database MyDatabase below is the code sample
use MyDatabase
SELECT t.name AS table_name,
SCHEMA_NAME(schema_id) AS schema_name,
c.name AS column_name
FROM sys.tables AS t
INNER JOIN sys.columns c ON t.OBJECT_ID = c.OBJECT_ID
WHERE c.name LIKE '%logintime%'
ORDER BY schema_name, table_name;
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
There are lots of workable answers already. I just wanted to share one I wrote that has additional functionality.
--=======================================================================
-- MSSQL Unified Search
-- Minimum compatibility level = 130 (SQL Server 2016)
-- NOTE: The minimum compatibility level is required by the built-in STRING_SPLIT() function.
-- However, you can create the STRING_SPLIT() function at the bottom of this script for
-- lower versions of MSSQL Server.
--
-- Usage:
-- Set the parameters below and execute this script.
--
/************************ Enter Parameters Here ************************/
/**/
/**/ DECLARE #SearchString VARCHAR(1000) = 'string to search for'; -- Accepts SQL wilcards
/**/
/**/ DECLARE #IncludeUserTables BIT = 1;
/**/ DECLARE #IncludeViews BIT = 0;
/**/ DECLARE #IncludeStoredProcedures BIT = 0;
/**/ DECLARE #IncludeFunctions BIT = 0;
/**/ DECLARE #IncludeTriggers BIT = 0;
/**/
/**/ DECLARE #DebugMode BIT = 0;
/**/ DECLARE #ExcludeColumnTypes NVARCHAR(500) = 'text, ntext, char, nchar, timestamp, bigint, tinyint, smallint, bit, date, time, smalldatetime, datetime, datetime2, real, money, float, decimal, binary, varbinary, image'; -- Comma delimited list
/**/
/***********************************************************************/
SET NOCOUNT ON;
SET #SearchString = QUOTENAME(#SearchString,'''');
DECLARE #Results TABLE ([ObjectType] NVARCHAR(200), [ObjectName] NVARCHAR(200), [ColumnName] NVARCHAR(400), [Value] NVARCHAR(MAX), [SelectStatement] NVARCHAR(1000));
DECLARE #ExcludeColTypes TABLE (system_type_id INT);
INSERT INTO #ExcludeColTypes ([system_type_id])
SELECT [system_type_id]
FROM sys.types WHERE
[name] IN (
SELECT LTRIM(RTRIM([value])) FROM STRING_SPLIT(#ExcludeColumnTypes,',')
);
DECLARE #ObjectType NVARCHAR(200);
DECLARE #ObjectName NVARCHAR(200);
DECLARE #Value NVARCHAR(MAX);
DECLARE #SelectStatement NVARCHAR(1000);
DECLARE #Query NVARCHAR(4000);
/********************* Table Objects *********************/
IF (#IncludeUserTables = 1)
BEGIN
DECLARE #TableObjectId INT = (SELECT MIN([object_id]) FROM sys.tables);
DECLARE #ColumnId INT;
WHILE #TableObjectId IS NOT NULL
BEGIN
SELECT #ObjectType = 'USER TABLE';
SELECT #ObjectName = '[' + SCHEMA_NAME([schema_id]) + '].[' + OBJECT_NAME(#TableObjectId) + ']' FROM sys.tables WHERE [object_id] = #TableObjectId;
SET #ColumnId = (SELECT MIN([column_id]) FROM sys.columns WHERE [system_type_id] NOT IN (SELECT [system_type_id] FROM #ExcludeColTypes) AND [object_id] = #TableObjectId);
WHILE #ColumnId IS NOT NULL
BEGIN
SELECT #Value = '[' + [name] +']' FROM sys.columns WHERE [object_id] = #TableObjectId AND column_id = #ColumnId;
SET #SelectStatement = 'SELECT * FROM ' + #ObjectName + ' WHERE CAST(' + #Value + ' AS NVARCHAR(4000)) LIKE ' + #SearchString + ';';
SET #Query = 'SELECT '
+ QUOTENAME(#ObjectType, '''')
+ ', ' + QUOTENAME(#ObjectName, '''')
+ ', ' + QUOTENAME(#Value, '''')
+ ', ' + #Value
+ ', ''' + REPLACE(#SelectStatement,'''','''''') + ''''
+ ' FROM ' + #ObjectName
+ ' WHERE CAST(' + #Value + ' AS NVARCHAR(4000)) LIKE ' + #SearchString + ';';
IF #DebugMode = 0
BEGIN
INSERT INTO #Results EXEC(#Query);
END;
ELSE
BEGIN
PRINT 'Select Statement: ' + #SelectStatement;
PRINT 'Query: ' + #Query;
END;
SET #ColumnId = (SELECT MIN([column_id]) FROM sys.columns WHERE [system_type_id] NOT IN (SELECT [system_type_id] FROM #ExcludeColTypes) AND [object_id] = #TableObjectId AND [column_id] > #ColumnId);
END;
SET #TableObjectId = (SELECT MIN([object_id]) FROM sys.tables WHERE [object_id] > #TableObjectId);
END;
END;
/********************* Objects Other than Tables *********************/
SET #Query = 'SELECT ' +
'ObjectType = CASE ' +
'WHEN b.[type] = ''V'' THEN ''VIEW'' ' +
'WHEN b.[type] = ''P'' THEN ''STORED PROCEDURE'' ' +
'WHEN b.[type] = ''FN'' THEN ''SCALAR-VALUED FUNCTION'' ' +
'WHEN b.[type] = ''IF'' THEN ''TABLE-VALUED FUNCTION'' ' +
'WHEN b.[type] = ''TR'' THEN ''TRIGGER'' ' +
'END ' +
',[ObjectName] = ''['' + SCHEMA_NAME(b.[schema_id]) + ''].['' + OBJECT_NAME(a.[object_id]) + '']'' ' +
',[ColumnName] = NULL ' +
',[Value] = a.[definition] ' +
',[SelectStatement] = ''SP_HELPTEXT '' + QUOTENAME(''['' + SCHEMA_NAME(b.[schema_id]) + ''].['' + OBJECT_NAME(a.[object_id]) + '']'','''''''') + '';'' ' +
'FROM [sys].[sql_modules] a ' +
'JOIN [sys].[objects] b ON a.[object_id] = b.[object_id] ' +
'WHERE ' +
'( ' +
' a.[definition] LIKE ' + #SearchString +
') ' +
'AND ' +
'( ' +
' ( ' +
CAST(#IncludeViews AS VARCHAR(1)) + ' = 1 ' +
' AND ' +
' b.[type] IN (''V'') ' +
' ) ' +
' OR ' +
' ( ' +
CAST(#IncludeStoredProcedures AS VARCHAR(1)) + ' = 1 ' +
' AND ' +
' b.[type] IN (''P'') ' +
' ) ' +
' OR ' +
' ( ' +
CAST(#IncludeFunctions AS VARCHAR(1)) + ' = 1 ' +
' AND ' +
' b.[type] IN (''FN'',''IF'') ' +
' ) ' +
' OR ' +
' ( ' +
CAST(#IncludeTriggers AS VARCHAR(1)) + ' = 1 ' +
' AND ' +
' b.[type] IN (''TR'') ' +
' ) ' +
'); ';
IF #DebugMode = 0
BEGIN
INSERT INTO #Results EXEC(#Query);
END;
ELSE
BEGIN
PRINT 'Select Statement: ' + #SelectStatement;
PRINT 'Query: ' + #Query;
END;
IF #DebugMode = 0
BEGIN
SELECT
[ObjectType]
,[ObjectName]
,[ColumnName]
,[Value]
,[Count] = CASE
WHEN [ObjectType] IN ('USER TABLE') THEN COUNT(1)
ELSE NULL
END
,[SelectStatement]
FROM #Results
GROUP BY [ObjectType], [ObjectName], [ColumnName], [Value], [SelectStatement]
ORDER BY [Value];
END;
/********************** STRING_SPLIT() FUNCTION **********************
CREATE FUNCTION STRING_SPLIT (
#Expression nvarchar(4000)
,#Delimiter nvarchar(100)
)
RETURNS #Ret TABLE ([value] NVARCHAR(4000))
AS
BEGIN
DECLARE #Start INT = 0, #End INT, #Length INT;
SELECT #End = CHARINDEX(#Delimiter,#Expression), #Length = #End - #Start;
IF #End <= 0
BEGIN
INSERT INTO #Ret ([value]) VALUES (#Expression);
END
ELSE
BEGIN
WHILE #Length >= 0
BEGIN
INSERT INTO #Ret ([value])
SELECT ltrim(rtrim(substring(#Expression,#Start,#Length)));
SELECT #Start = #End + LEN(#Delimiter)
SELECT #End = CHARINDEX(#Delimiter,#Expression,#Start)
IF #End < 1
SELECT #End = LEN(#Expression) + 1;
SELECT #Length = #End - #Start;
END;
END;
RETURN;
END;
*********************************************************************/
By far the best and most universal solution I found is to pipe a dump of the db through to a grep of what you are searching for.
e.g. for Mysql:
mysqldump -pPASSWORD database | grep 'search phrase'
Or if you get too many results, you can then output them to a file:
mysqldump -pPASSWORD database | grep 'search phrase' > results.txt
Consider have a table like named : People
| Id | Name | Code |
| 1 | John | 857 |
| 2 | Mike | 893 |
| 3 | Sara | 935 |
This table is in PeopleDb Database
Now I want to find 'Mike' keyword. Situation :
I don't know to search in which database, tables.
I need a query that searches in all databases and tables and shows me this :
| Id | DatabaseName | TableName | ColumnName | Pk | SearchValue
| 1 | 'PeopleDb' | 'People' | 'Name' | 2 | 'Mike'
I don't know how to write the query to search in all databases and tables.
Any help will be greatly appreciated.
Edit :
Speed is not an issue here and I need to do this.
I tried this query, I want the same but that searches all databases.
CREATE PROC SearchAllTables
(
#SearchStr nvarchar(100)
)
AS
BEGIN
-- Copyright © 2002 Narayana Vyas Kondreddi.All rights reserved.
-- Purpose: To search all columns of all tables for a given search string
-- Written by: Narayana Vyas Kondreddi
-- Site: http://vyaskn.tripod.com
-- Tested on: SQL Server 7.0 and SQL Server 2000
-- Date modified: 28th July 2002 22:50 GMT
DECLARE #Results TABLE(ColumnName nvarchar(370), ColumnValue nvarchar(3630))
SET NOCOUNT ON
DECLARE #TableName nvarchar(256), #ColumnName nvarchar(128), #SearchStr2 nvarchar(110)
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 ''' + #TableName + '.' + #ColumnName + ''', LEFT(' + #ColumnName + ', 3630)
FROM ' + #TableName + ' (NOLOCK) ' +
' WHERE ' + #ColumnName + ' LIKE ' + #SearchStr2
)
END
END
END
SELECT ColumnName, ColumnValue FROM #Results
END
Update :
I need a working T-Sql that searches all databases, tables, columns, all type of variables.
Current answers will not work in some situations like Connection String in nvarchar field.
I have updated your Logic as per below and it works fine, please have a look:
DECLARE #SearchStr VARCHAR(50)='Surat'
DECLARE #Results TABLE(DatabaseName NVARCHAR(500), TableName nvarchar(370),ColumnName nvarchar(370), ColumnValue nvarchar(3630),PrimaryKey nvarchar(200), PrimaryKeyValue nvarchar(4000))
SET NOCOUNT ON
DECLARE #TableList AS Table
(
TableName VARCHAR(500),
RowNo INT
)
DECLARE #ColumnList AS Table
(
ColumnName VARCHAR(500),
RowNo INT
)
DECLARE #PrimaryKeyList AS Table
(
PrimaryKeyName VARCHAR(500)
)
DECLARE #TableName nvarchar(256), #ColumnName nvarchar(128), #SearchStr2 nvarchar(110), #PrimaryKey nvarchar(200), #CurrentTableName nvarchar(256)
SET #TableName = ''
SET #SearchStr2 = QUOTENAME('%' + #SearchStr + '%', '''')
DECLARE #DatabaseCount INT=0, #Index INT=0, #DatabaseName NVARCHAR(500), #TotalColumnCount INT, #ColumnIndex INT=0, #TotalTableCount INT, #TableIndex INT=0
SELECT
*,
ROW_NUMBER() OVER (ORDER BY name) AS RowNo
INTO #tblDatabases
FROM Sys.Databases
WHERE name NOT IN ('master','model','msdb','tempdb')
SELECT #DatabaseCount=COUNT (*) FROM #tblDatabases
WHILE #Index<#DatabaseCount
BEGIN
SET #Index=#Index+1
SELECT #DatabaseName='',#TableIndex=0,#ColumnIndex=0,#TableName='',#ColumnName=''
SELECT #DatabaseName=name FROM #tblDatabases WHERE RowNo=#Index
DELETE FROM #TableList
INSERT INTO #TableList
EXEC('
SELECT QUOTENAME(TABLE_SCHEMA) + ''.'' + QUOTENAME(TABLE_NAME),
ROW_NUMBER() OVER (ORDER BY TABLE_NAME)
FROM ['+#DatabaseName+'].INFORMATION_SCHEMA.TABLES
WHERE TABLE_TYPE = ''BASE TABLE''
')
SELECT #TotalTableCount=COUNT(*) FROM #TableList
WHILE #TableIndex<#TotalTableCount
BEGIN
SET #TableIndex=#TableIndex+1
SELECT #ColumnName = '',#ColumnIndex=0
SELECT #TableName=TableName FROM #TableList WHERE RowNo=#TableIndex
SET #CurrentTableName=REPLACE(REPLACE(REPLACE(#TableName,'[dbo].',''),'[',''),']','')
DELETE FROM #ColumnList
INSERT INTO #ColumnList
EXEC('SELECT
COLUMN_NAME,ROW_NUMBER() OVER (ORDER BY COLUMN_NAME)
FROM ['+#DatabaseName+'].INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_SCHEMA = PARSENAME('''+#TableName+''', 2)
AND TABLE_NAME = PARSENAME('''+#TableName+''', 1)
AND DATA_TYPE IN (''char'', ''varchar'', ''nchar'', ''nvarchar'')
')
SELECT #TotalColumnCount=COUNT(*) FROM #ColumnList
WHILE #ColumnIndex<#TotalColumnCount
BEGIN
SET #ColumnIndex=#ColumnIndex+1
SET #ColumnName=''
SELECT #ColumnName=ColumnName FROM #ColumnList WHERE RowNo=#ColumnIndex
DELETE FROM #PrimaryKeyList
INSERT INTO #PrimaryKeyList
EXEC('
SELECT Col.Column_Name from
['+#DatabaseName+'].INFORMATION_SCHEMA.TABLE_CONSTRAINTS Tab,
['+#DatabaseName+'].INFORMATION_SCHEMA.CONSTRAINT_COLUMN_USAGE Col
WHERE
Col.Constraint_Name = Tab.Constraint_Name
AND Col.Table_Name = Tab.Table_Name
AND Constraint_Type = ''PRIMARY KEY''
AND Col.Table_Name= '''+#CurrentTableName+'''
')
SELECT #PrimaryKey=''
SELECT #PrimaryKey=PrimaryKeyName FROM #PrimaryKeyList
SET #PrimaryKey=ISNULL(#PrimaryKey,'')
IF #ColumnName IS NOT NULL AND #PrimaryKey<>''
BEGIN
INSERT INTO #Results
EXEC
(
'SELECT '''+#DatabaseName+''','''+#CurrentTableName+''',''' + #ColumnName + ''', LEFT(' + #ColumnName + ', 3630) , '''+#PrimaryKey+''', [' + #PrimaryKey + ']
FROM ['+#DatabaseName+'].' + #TableName + ' (NOLOCK) ' +
' WHERE ' + #ColumnName + ' LIKE ' + #SearchStr2
)
END
END
END
END
SELECT ROW_NUMBER() OVER (ORDER BY DatabaseName) AS Id,DatabaseName,TableName,ColumnName, ColumnValue AS SearchValue,PrimaryKeyValue AS Pk, PrimaryKey FROM #Results
DROP TABLE #tblDatabases
SELECT * FROM all_objects where object_name = 'XXXX';
you can use this Store Procedure
CREATE PROCEDURE dbo.SearchAllDatabases
#SearchTerm NVARCHAR(255) = NULL
AS
BEGIN
SET NOCOUNT ON;
SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
IF #SearchTerm IS NULL OR #SearchTerm NOT LIKE N'%[^%^_]%'
BEGIN
RAISERROR(N'Please enter a valid search term.', 11, 1);
RETURN;
END
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];
END
GO
This seems like a crazy thing to do - the search could completely kill your server. That said, if this is a one-off/occasional use manual run kind of thing then you can create a script to generate the SQL commands you need and then execute the result sets. I've done this sort of thing before to refactor columns in a database.
Your script would need to first run a query to get the names of all the DBs on your sql-server instance
SELECT * FROM sys.databases
Then create dynamic sql including the USE command to specify the DB and use the information_schema.tables and .columns to get the names of all the tables and columns you want to search - up to you how you decided to select the columns to be searched (is it just columns like N'%name%' for example.
Then use this information in a for loop to create individual table/column searches. For efficiency (and to help you debug if it's not working) I suggest utilise #table variables.
Finally select the contents of any #tables holding the table queries you've created.
This output can then be run on the server - providing you've included the use commands or prefixed table names with [dbname].[schema].
CREATE TABLE myTable99 (TABLE_NAME sysname, COLUMN_NAME sysname, Occurs int)
GO
SET NOCOUNT ON
DECLARE #SQL varchar(8000),
#TABLE_NAME sysname,
#COLUMN_NAME sysname,
#Sargable varchar(80),
#Count int
SELECT #Sargable = 'PS'
DECLARE insaneCursor CURSOR FOR
SELECT c.TABLE_NAME, c.COLUMN_NAME
FROM INFORMATION_SCHEMA.Columns c INNER JOIN INFORMATION_SCHEMA.Tables t
ON t.TABLE_SCHEMA = c.TABLE_SCHEMA AND t.TABLE_NAME = c.TABLE_NAME
WHERE c.DATA_TYPE IN ('char','nchar','varchar','nvarchar','text','ntext')
AND t.TABLE_TYPE = 'BASE TABLE'
OPEN insaneCursor
FETCH NEXT FROM insaneCursor INTO #TABLE_NAME, #COLUMN_NAME
WHILE ##FETCH_STATUS = 0
BEGIN
SELECT #SQL = 'INSERT INTO myTable99 (TABLE_NAME, COLUMN_NAME, Occurs) SELECT '
+ '''' + #TABLE_NAME + '''' + ','
+ '''' + #COLUMN_NAME + '''' + ','
+ 'COUNT(*) FROM [' + #TABLE_NAME
+ '] WHERE [' + #COLUMN_NAME + '] Like '
+ ''''+ '%' + #Sargable + '%' + ''''
--SELECT #SQL
EXEC(#SQL)
IF ##ERROR <> 0
------ <> means Not Equal To
BEGIN
SELECT #SQL
SELECT * FROM INFORMATION_SCHEMA.Columns WHERE TABLE_NAME = #TABLE_NAME
GOTO Error
END
FETCH NEXT FROM insaneCursor INTO #TABLE_NAME, #COLUMN_NAME
END
SELECT * FROM myTable99 WHERE Occurs <> 0
Error:
CLOSE insaneCursor
DEALLOCATE insaneCursor
GO
DROP TABLE myTable99
GO
SET NOCOUNT OFF
The following stored procedure will search for the string 'PS' and will return the COLUMN_NAME and TABLE_NAME but I want the ID value of the PS in corresponding column
ex:
ID NAME
2 PW
3 PS
now stored procedure only returns COLUMN_NAME,TABLE_NAME but I need the ID that is 3 when I search for string 'PS' along with COLUMN_NAME and TABLE_NAME
I tried with
SELECT #SQL = 'INSERT INTO myTable99 (TABLE_NAME, COLUMN_NAME, Occurs) SELECT *'
+ 'FROM [' + #TABLE_NAME
+ '] WHERE [' + #COLUMN_NAME + '] Like '
+ ''''+ '%' + #Sargable + '%' + ''''
but the stored procedure returned all table and column name in database even if the string is not found in table
myTable99
TABLE_NAME COLUMN_NAME Occurs
project projectname 2
task name 1
Now I need a new column with name ID which fetches the ID of the projectname 'PS' in table project
Expected result:
Suppose table Project has PS entry
Table name: Project
Columns:
ID projectname
2 PR
3 PS
Now the stored procedure will return the Table_Name=Project,column_Name=projectname but not the Id, I need ID of the string PS that is 3
Result: when I search for string='PS'
ID TABLE_NAME COLUMN_NAME Occurs
3 Project projectname 1
Your question is not very clear, I think you need to bring the projectId along with rest of the columns in myTable99. You can do following.
--++++++++++++++++++++++++++++++++++++++++++++++++
--Before/after your cursor (not within the cursor)
DECLARE #ProjectId INT
--Assuming projectName as a unique constraint
SELECT #ProjectId = ProjectId
FROM yourProjectTable
WHERE projectName = #Sargable
--++++++++++++++++++++++++++++++++++++++++++++++++
--At the end, replace your select query with
SELECT TABLE_NAME, COLUMN_NAME, Occurs, #ProjectId ProjectId
FROM myTable99
WHERE Occurs <> 0
I am using the code below in a trigger. I have two columns that are updated by a windows service every 60 minutes in the table I am monitoring. How can I ignore the two columns from writing to the audit table.
ALTER trigger [dbo].[tMonitors_ChangeTracking] on [dbo].[tMonitors] for insert, update, delete
as
declare #bit int,
#field int,
#maxfield int,
#char int,
#fieldname varchar(128),
#TableName varchar(128),
#PKCols varchar(1000),
#sql varchar(2000),
#UpdateDate varchar(21),
#UserName varchar(128),
#Type char(1),
#PKFieldSelect varchar(1000),
#PKValueSelect varchar(1000)
select #TableName = 'tMonitors'
-- date and user
select #UserName = system_user ,
#UpdateDate = convert(varchar(8), getdate(), 112) + ' ' + convert(varchar(12), getdate(), 114)
-- Action
if exists (select * from inserted)
if exists (select * from deleted)
select #Type = 'U'
else
select #Type = 'I'
else
select #Type = 'D'
-- get list of columns
select * into #ins from inserted
select * into #del from deleted
-- Get primary key columns for full outer join
select #PKCols = coalesce(#PKCols + ' and', ' on') + ' i.' + c.COLUMN_NAME + ' = d.' + c.COLUMN_NAME
from INFORMATION_SCHEMA.TABLE_CONSTRAINTS pk ,
INFORMATION_SCHEMA.KEY_COLUMN_USAGE c
where pk.TABLE_NAME = #TableName
and CONSTRAINT_TYPE = 'PRIMARY KEY'
and c.TABLE_NAME = pk.TABLE_NAME
and c.CONSTRAINT_NAME = pk.CONSTRAINT_NAME
-- Get primary key fields select for insert
select #PKFieldSelect = coalesce(#PKFieldSelect+'+','') + '''' + COLUMN_NAME + ''''
from INFORMATION_SCHEMA.TABLE_CONSTRAINTS pk ,
INFORMATION_SCHEMA.KEY_COLUMN_USAGE c
where pk.TABLE_NAME = #TableName
and CONSTRAINT_TYPE = 'PRIMARY KEY'
and c.TABLE_NAME = pk.TABLE_NAME
and c.CONSTRAINT_NAME = pk.CONSTRAINT_NAME
select #PKValueSelect = coalesce(#PKValueSelect+'+','') + 'convert(varchar(100), coalesce(i.' + COLUMN_NAME + ',d.' + COLUMN_NAME + '))'
from INFORMATION_SCHEMA.TABLE_CONSTRAINTS pk ,
INFORMATION_SCHEMA.KEY_COLUMN_USAGE c
where pk.TABLE_NAME = #TableName
and CONSTRAINT_TYPE = 'PRIMARY KEY'
and c.TABLE_NAME = pk.TABLE_NAME
and c.CONSTRAINT_NAME = pk.CONSTRAINT_NAME
if #PKCols is null
begin
raiserror('no PK on table %s', 16, -1, #TableName)
return
end
select #field = 0, #maxfield = max(ORDINAL_POSITION) from INFORMATION_SCHEMA.COLUMNS where TABLE_NAME = #TableName
while #field < #maxfield
begin
select #field = min(ORDINAL_POSITION) from INFORMATION_SCHEMA.COLUMNS where TABLE_NAME = #TableName and ORDINAL_POSITION > #field
select #bit = (#field - 1 )% 8 + 1
select #bit = power(2,#bit - 1)
select #char = ((#field - 1) / 8) + 1
if substring(COLUMNS_UPDATED(),#char, 1) & #bit > 0 or #Type in ('I','D')
begin
select #fieldname = COLUMN_NAME from INFORMATION_SCHEMA.COLUMNS where TABLE_NAME = #TableName and ORDINAL_POSITION = #field
select #sql = 'insert tMonitors_Audit (Type, TableName, PrimaryKeyField, PrimaryKeyValue, FieldName, OldValue, NewValue, UpdateDate, UserName)'
select #sql = #sql + ' select ''' + #Type + ''''
select #sql = #sql + ',''' + #TableName + ''''
select #sql = #sql + ',' + #PKFieldSelect
select #sql = #sql + ',' + #PKValueSelect
select #sql = #sql + ',''' + #fieldname + ''''
select #sql = #sql + ',convert(varchar(1000),d.' + #fieldname + ')'
select #sql = #sql + ',convert(varchar(1000),i.' + #fieldname + ')'
select #sql = #sql + ',''' + #UpdateDate + ''''
select #sql = #sql + ',''' + #UserName + ''''
select #sql = #sql + ' from #ins i full outer join #del d'
select #sql = #sql + #PKCols
select #sql = #sql + ' where i.' + #fieldname + ' <> d.' + #fieldname
select #sql = #sql + ' or (i.' + #fieldname + ' is null and d.' + #fieldname + ' is not null)'
select #sql = #sql + ' or (i.' + #fieldname + ' is not null and d.' + #fieldname + ' is null)'
exec (#sql)
end
end
The simple approach, assuming these columns to ignore are only updated during this hourly process:
IF NOT (UPDATE(col_to_ignore_1) AND UPDATE(col_to_ignore_2))
BEGIN
...
EXEC(#sql);
END
Otherwise you can build a similar list based on INFORMATION_SCHEMA.COLUMNS, so that the logging only happens when at least one of the other columns is updated, that would end up like this:
IF (UPDATE(col_to_audit_1) OR UPDATE(col_to_audit_2) ... )
BEGIN
...
EXEC(#sql);
END
It is not clear from your question whether you want to ignore these two columns always, or only when this hourly process runs. Perhaps another idea is to use a transaction and disable the trigger for this update... it will obviously make the trigger much less complicated.
You can specify which columns you want to pay attention to by using the "UPDATE(column_name)" syntax, like so:
CREATE TRIGGER trigger_name ON tablename
FOR insert, update, delete
AS
SET NOCOUNT ON
IF ( UPDATE(Column1) OR UPDATE(Column2))
BEGIN
--your sql here
END
Other options are available at the official documentation.
You can access the complete list of columns changed using COLUMNS_UPDATED() and compare it to pre-defined bit patterns. For tables with many columns, calculating the bit positions can be easier than listing out UPDATED(every) OR UPDATED(other) OR UPDATED(column).
For example, for a table:
CREATE TABLE Users
(
UserID INT NOT NULL PRIMARY KEY IDENTITY,
Name nvarchar(255) NOT NULL,
EmailAddress nvarchar(255) NOT NULL,
LastPageViewDate datetime NULL,
GroupID INT NOT NULL
);
where you want to ignore updates to LastPageViewDate. You can determine the bitmask via:
SELECT name, column_id FROM sys.columns WHERE object_id = OBJECT_ID('dbo.Users')
name column_id
-------------------- -----------
UserID 1
Name 2
EmailAddress 3
LastPageViewDate 4
GroupID 5
The trigger can then check for the little-endian bitmask 0x08 ignoring trailing 0's:
CREATE TRIGGER dbo.TR_IUD_Users_LogEdit
ON dbo.Users
AFTER INSERT, UPDATE
AS
BEGIN
SET NOCOUNT ON;
-- Ignore page view logging caused by
-- UPDATE Users SET LastPageViewDate = GETDATE() WHERE UserID = #UserID
-- Bit 4 == LastPageViewDate
IF COLUMNS_UPDATED() = 0x08 RETURN;
-- For forward compatibility, you can ignore unchanged new columns added
-- by RTRIM'ing the '0's (required since 0x08 != 0x0800)
--
--IF REPLACE(RTRIM(REPLACE(CONVERT(varchar(max), COLUMNS_UPDATED(), 2), '0', ' ')), ' ', '0') IN ('08')
-- RETURN;
/* Snipped trigger body */
END
GO
I am lost in a big database and I am not able to find where the data I get comes from. I was wondering if it is possible with SQL Server 2005 to search for a string in all tables, rows and columns of a database?
Does anybody has an idea if it is possible and how?
This code should do it in SQL 2005, but a few caveats:
It is RIDICULOUSLY slow. I tested it on a small database that I have with only a handful of tables and it took many minutes to complete. If your database is so big that you can't understand it then this will probably be unusable anyway.
I wrote this off the cuff. I didn't put in any error handling and there might be some other sloppiness especially since I don't use cursors often. For example, I think there's a way to refresh the columns cursor instead of closing/deallocating/recreating it every time.
If you can't understand the database or don't know where stuff is coming from, then you should probably find someone who does. Even if you can find where the data is, it might be duplicated somewhere or there might be other aspects of the database that you don't understand. If no one in your company understands the database then you're in a pretty big mess.
DECLARE
#search_string VARCHAR(100),
#table_name SYSNAME,
#table_schema SYSNAME,
#column_name SYSNAME,
#sql_string VARCHAR(2000)
SET #search_string = 'Test'
DECLARE tables_cur CURSOR FOR SELECT TABLE_SCHEMA, TABLE_NAME FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_TYPE = 'BASE TABLE'
OPEN tables_cur
FETCH NEXT FROM tables_cur INTO #table_schema, #table_name
WHILE (##FETCH_STATUS = 0)
BEGIN
DECLARE columns_cur CURSOR FOR SELECT COLUMN_NAME FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_SCHEMA = #table_schema AND TABLE_NAME = #table_name AND COLLATION_NAME IS NOT NULL -- Only strings have this and they always have it
OPEN columns_cur
FETCH NEXT FROM columns_cur INTO #column_name
WHILE (##FETCH_STATUS = 0)
BEGIN
SET #sql_string = 'IF EXISTS (SELECT * FROM ' + QUOTENAME(#table_schema) + '.' + QUOTENAME(#table_name) + ' WHERE ' + QUOTENAME(#column_name) + ' LIKE ''%' + #search_string + '%'') PRINT ''' + QUOTENAME(#table_schema) + '.' + QUOTENAME(#table_name) + ', ' + QUOTENAME(#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_schema, #table_name
END
CLOSE tables_cur
DEALLOCATE tables_cur
I’d suggest you find yourself a 3rd party tool for this such as ApexSQL Search (there are probably others out there too but I use this one because it’s free).
If you really want to go the SQL way you can try using stored procedure created by
Sorna Kumar Muthuraj – copied code is below. Just execute this stored procedure for all tables in your schema (easy with dynamics SQL)
CREATE PROCEDURE SearchTables
#Tablenames VARCHAR(500)
,#SearchStr NVARCHAR(60)
,#GenerateSQLOnly Bit = 0
AS
/*
Parameters and usage
#Tablenames -- Provide a single table name or multiple table name with comma seperated.
If left blank , it will check for all the tables in the database
#SearchStr -- Provide the search string. Use the '%' to coin the search.
EX : X%--- will give data staring with X
%X--- will give data ending with X
%X%--- will give data containig X
#GenerateSQLOnly -- Provide 1 if you only want to generate the SQL statements without seraching the database.
By default it is 0 and it will search.
Samples :
1. To search data in a table
EXEC SearchTables #Tablenames = 'T1'
,#SearchStr = '%TEST%'
The above sample searches in table T1 with string containing TEST.
2. To search in a multiple table
EXEC SearchTables #Tablenames = 'T2'
,#SearchStr = '%TEST%'
The above sample searches in tables T1 & T2 with string containing TEST.
3. To search in a all table
EXEC SearchTables #Tablenames = '%'
,#SearchStr = '%TEST%'
The above sample searches in all table with string containing TEST.
4. Generate the SQL for the Select statements
EXEC SearchTables #Tablenames = 'T1'
,#SearchStr = '%TEST%'
,#GenerateSQLOnly = 1
*/
SET NOCOUNT ON
DECLARE #CheckTableNames Table
(
Tablename sysname
)
DECLARE #SQLTbl TABLE
(
Tablename SYSNAME
,WHEREClause VARCHAR(MAX)
,SQLStatement VARCHAR(MAX)
,Execstatus BIT
)
DECLARE #sql VARCHAR(MAX)
DECLARE #tmpTblname sysname
IF LTRIM(RTRIM(#Tablenames)) IN ('' ,'%')
BEGIN
INSERT INTO #CheckTableNames
SELECT Name
FROM sys.tables
END
ELSE
BEGIN
SELECT #sql = 'SELECT ''' + REPLACE(#Tablenames,',',''' UNION SELECT ''') + ''''
INSERT INTO #CheckTableNames
EXEC(#sql)
END
INSERT INTO #SQLTbl
( Tablename,WHEREClause)
SELECT SCh.name + '.' + ST.NAME,
(
SELECT '[' + SC.name + ']' + ' LIKE ''' + #SearchStr + ''' OR ' + CHAR(10)
FROM SYS.columns SC
JOIN SYS.types STy
ON STy.system_type_id = SC.system_type_id
AND STy.user_type_id =SC.user_type_id
WHERE STY.name in ('varchar','char','nvarchar','nchar')
AND SC.object_id = ST.object_id
ORDER BY SC.name
FOR XML PATH('')
)
FROM SYS.tables ST
JOIN #CheckTableNames chktbls
ON chktbls.Tablename = ST.name
JOIN SYS.schemas SCh
ON ST.schema_id = SCh.schema_id
WHERE ST.name <> 'SearchTMP'
GROUP BY ST.object_id, SCh.name + '.' + ST.NAME ;
UPDATE #SQLTbl
SET SQLStatement = 'SELECT * INTO SearchTMP FROM ' + Tablename + ' WHERE ' + substring(WHEREClause,1,len(WHEREClause)-5)
DELETE FROM #SQLTbl
WHERE WHEREClause IS NULL
WHILE EXISTS (SELECT 1 FROM #SQLTbl WHERE ISNULL(Execstatus ,0) = 0)
BEGIN
SELECT TOP 1 #tmpTblname = Tablename , #sql = SQLStatement
FROM #SQLTbl
WHERE ISNULL(Execstatus ,0) = 0
IF #GenerateSQLOnly = 0
BEGIN
IF OBJECT_ID('SearchTMP','U') IS NOT NULL
DROP TABLE SearchTMP
EXEC (#SQL)
IF EXISTS(SELECT 1 FROM SearchTMP)
BEGIN
SELECT Tablename=#tmpTblname,* FROM SearchTMP
END
END
ELSE
BEGIN
PRINT REPLICATE('-',100)
PRINT #tmpTblname
PRINT REPLICATE('-',100)
PRINT replace(#sql,'INTO SearchTMP','')
END
UPDATE #SQLTbl
SET Execstatus = 1
WHERE Tablename = #tmpTblname
END
SET NOCOUNT OFF
go
Although the solutions presented before are valid and work, I humbly offer a code that's cleaner, more elegant, and with better performance, at least as I see it.
Firstly, one may ask: Why would anyone ever need a code snippet to globally and blindly look for a string? Hey, they already invented fulltext, don't you know?
My answer: my mainly work is at systems integration projects, and discovering where the data is written is important whenever I'm learning a new and undocummented database, which seldom happens.
Also, the code I present is a stripped down version of a more powerful and dangerous script that searches and REPLACES text throughout the database.
CREATE TABLE #result(
id INT IDENTITY, -- just for register seek order
tblName VARCHAR(255),
colName VARCHAR(255),
qtRows INT
)
go
DECLARE #toLookFor VARCHAR(255)
SET #toLookFor = '[input your search criteria here]'
DECLARE cCursor CURSOR LOCAL FAST_FORWARD FOR
SELECT
'[' + usr.name + '].[' + tbl.name + ']' AS tblName,
'[' + col.name + ']' AS colName,
LOWER(typ.name) AS typName
FROM
sysobjects tbl
INNER JOIN(
syscolumns col
INNER JOIN systypes typ
ON typ.xtype = col.xtype
)
ON col.id = tbl.id
--
LEFT OUTER JOIN sysusers usr
ON usr.uid = tbl.uid
WHERE tbl.xtype = 'U'
AND LOWER(typ.name) IN(
'char', 'nchar',
'varchar', 'nvarchar',
'text', 'ntext'
)
ORDER BY tbl.name, col.colorder
--
DECLARE #tblName VARCHAR(255)
DECLARE #colName VARCHAR(255)
DECLARE #typName VARCHAR(255)
--
DECLARE #sql NVARCHAR(4000)
DECLARE #crlf CHAR(2)
SET #crlf = CHAR(13) + CHAR(10)
OPEN cCursor
FETCH cCursor
INTO #tblName, #colName, #typName
WHILE ##fetch_status = 0
BEGIN
IF #typName IN('text', 'ntext')
BEGIN
SET #sql = ''
SET #sql = #sql + 'INSERT INTO #result(tblName, colName, qtRows)' + #crlf
SET #sql = #sql + 'SELECT #tblName, #colName, COUNT(*)' + #crlf
SET #sql = #sql + 'FROM ' + #tblName + #crlf
SET #sql = #sql + 'WHERE PATINDEX(''%'' + #toLookFor + ''%'', ' + #colName + ') > 0' + #crlf
END
ELSE
BEGIN
SET #sql = ''
SET #sql = #sql + 'INSERT INTO #result(tblName, colName, qtRows)' + #crlf
SET #sql = #sql + 'SELECT #tblName, #colName, COUNT(*)' + #crlf
SET #sql = #sql + 'FROM ' + #tblName + #crlf
SET #sql = #sql + 'WHERE ' + #colName + ' LIKE ''%'' + #toLookFor + ''%''' + #crlf
END
EXECUTE sp_executesql
#sql,
N'#tblName varchar(255), #colName varchar(255), #toLookFor varchar(255)',
#tblName, #colName, #toLookFor
FETCH cCursor
INTO #tblName, #colName, #typName
END
SELECT *
FROM #result
WHERE qtRows > 0
ORDER BY id
GO
DROP TABLE #result
go
If you are "getting data" from an application, the sensible thing would be to use the profiler and profile the database while running the application. Trace it, then search the results for that string.
The SSMS Tools PACK Add-In (Add-On) for Microsoft SQL Server Management Studio and Microsoft SQL Server Management Studio Express will do exactly what you need. On larger database it takes some time to search, but that is to be expected. It also includes a ton of cool features that should have be included with SQL Server Management Studio in the first place. Give it a try www.ssmstoolspack.com/
You do need to have SP2 for SQL Server Management Studio installed to run the tools.
I adapted a script originally written by Narayana Vyas Kondreddi in 2002. I changed the where clause to check text/ntext fields as well, by using patindex rather than like. I also changed the results table slightly. Unreasonably, I changed variable names, and aligned as I prefer (no disrespect to Mr. Kondretti). The user may want to change the data types searched. I used a global table to allow querying mid-processing, but a permanent table might be a smarter way to go.
/* original script by Narayana Vyas Kondreddi, 2002 */
/* adapted by Oliver Holloway, 2009 */
/* these lines can be replaced by use of input parameter for a proc */
declare #search_string varchar(1000);
set #search_string = 'what.you.are.searching.for';
/* create results table */
create table ##string_locations (
table_name varchar(1000),
field_name varchar(1000),
field_value varchar(8000)
)
;
/* special settings */
set nocount on
;
/* declare variables */
declare
#table_name varchar(1000),
#field_name varchar(1000)
;
/* variable settings */
set #table_name = ''
;
set #search_string = QUOTENAME('%' + #search_string + '%','''')
;
/* for each table */
while #table_name is not null
begin
set #field_name = ''
set #table_name = (
select MIN(QUOTENAME(table_schema) + '.' + QUOTENAME(table_name))
from INFORMATION_SCHEMA.TABLES
where
table_type = 'BASE TABLE' and
QUOTENAME(table_schema) + '.' + QUOTENAME(table_name) > #table_name and
OBJECTPROPERTY(OBJECT_ID(QUOTENAME(table_schema) + '.' + QUOTENAME(table_name)), 'IsMSShipped') = 0
)
/* for each string-ish field */
while (#table_name is not null) and (#field_name is not null)
begin
set #field_name = (
select MIN(QUOTENAME(column_name))
from INFORMATION_SCHEMA.COLUMNS
where
table_schema = PARSENAME(#table_name, 2) and
table_name = PARSENAME(#table_name, 1) and
data_type in ('char', 'varchar', 'nchar', 'nvarchar', 'text', 'ntext') and
QUOTENAME(column_name) > #field_name
)
/* search that field for the string supplied */
if #field_name is not null
begin
insert into ##string_locations
exec(
'select ''' + #table_name + ''',''' + #field_name + ''',' + #field_name +
'from ' + #table_name + ' (nolock) ' +
'where patindex(' + #search_string + ',' + #field_name + ') > 0' /* patindex works with char & text */
)
end
;
end
;
end
;
/* return results */
select table_name, field_name, field_value from ##string_locations (nolock)
;
/* drop temp table */
--drop table ##string_locations
;
Other answers posted already may work equally well or better, but I haven't used them. However, the following SQL I have used, and it really helped me out when I was trying to reverse-engineer a big system with a huge (and very unorganzied) SQL Server database.
This isn't my code. I wish I could credit the original author, but I can't find the link to the article anymore :(
Use
go
declare #SearchChar varchar(8000)
Set #SearchChar = -- Like 'A%', '11/11/2006'
declare #CMDMain varchar(8000), #CMDMainCount varchar(8000),#CMDJoin varchar(8000)
declare #ColumnName varchar(100),#TableName varchar(100)
declare dbTable cursor for
SELECT
Distinct b.Name as TableName
FROM
sysobjects b
WHERE
b.type='u' and b.Name 'dtproperties'
order by b.name
open dbTable
fetch next from dbTable into #TableName
WHILE ##FETCH_STATUS = 0
BEGIN
declare db cursor for
SELECT
c.Name as ColumnName
FROM
sysobjects b,
syscolumns c
WHERE
C.id = b.id and
b.type='u' and b.Name = #TableName
order by b.name
open db
fetch next from db into #ColumnName
set #CMDMain = 'SELECT ' + char(39) + #TableName + char(39) + ' as TableName,'+
' ['+ #TableName + '].* FROM [' + #TableName + ']'+
' WHERE '
set #CMDMainCount = 'SELECT Count(*) FROM [' + #TableName + '] Where '
Set #CMDJoin = ''
WHILE ##FETCH_STATUS = 0
BEGIN
set #CMDJoin = #CMDJoin + 'Convert(varchar(5000),[' +#ColumnName + ']) like ' + char(39) + #SearchChar + char(39) + ' OR '
fetch next from db into #ColumnName
end
close db
deallocate db
Set #CMDMainCount = 'If ('+ #CMDMainCount + Left(#CMDJoin, len(#CMDJoin) - 3)+ ') > 0 Begin '
Set #CMDMain = #CMDMainCount + #CMDMain + Left(#CMDJoin, len(#CMDJoin) - 3)
Set #CMDMain = #CMDMain + ' End '
Print #CMDMain
exec (#CMDMain)
fetch next from dbTable into #TableName
end
close dbTable
deallocate dbTable
Actually Im agree with MikeW (+1) it's better to use profiler for this case.
Anyway, if you really need to grab all (n)varchar columns in db and make a search. See below.
I suppose to use INFORMATION_SCHEMA.Tables + dynamic SQL.
The plain search:
DECLARE #SearchText VARCHAR(100)
SET #SearchText = '12'
DECLARE #Tables TABLE(N INT, TableName VARCHAR(100), ColumnNamesCSV VARCHAR(2000), SQL VARCHAR(4000))
INSERT INTO #Tables (TableName, ColumnNamesCSV)
SELECT T.TABLE_NAME AS TableName,
( SELECT C.Column_Name + ','
FROM INFORMATION_SCHEMA.Columns C
WHERE T.TABLE_NAME = C.TABLE_NAME
AND C.DATA_TYPE IN ('nvarchar','varchar')
FOR XML PATH('')
)
FROM INFORMATION_SCHEMA.Tables T
DELETE FROM #Tables WHERE ColumnNamesCSV IS NULL
INSERT INTO #Tables (N, TableName, ColumnNamesCSV)
SELECT ROW_NUMBER() OVER(ORDER BY TableName), TableName, ColumnNamesCSV
FROM #Tables
DELETE FROM #Tables WHERE N IS NULL
UPDATE #Tables
SET ColumnNamesCSV = SUBSTRING(ColumnNamesCSV, 0, LEN(ColumnNamesCSV))
UPDATE #Tables
SET SQL = 'SELECT * FROM ['+TableName+'] WHERE '''+#SearchText+''' IN ('+ColumnNamesCSV+')'
DECLARE #C INT,
#I INT,
#SQL VARCHAR(4000)
SELECT #I = 1,
#C = COUNT(1)
FROM #Tables
WHILE #I <= #C BEGIN
SELECT #SQL = SQL FROM #Tables WHERE N = #I
SET #I = #I+1
EXEC(#SQL)
END
and one with LIKE clause:
DECLARE #SearchText VARCHAR(100)
SET #SearchText = '12'
DECLARE #Tables TABLE(N INT, TableName VARCHAR(100), ColumnNamesCSVLike VARCHAR(2000), LIKESQL VARCHAR(4000))
INSERT INTO #Tables (TableName, ColumnNamesCSVLike)
SELECT T.TABLE_NAME AS TableName,
( SELECT C.Column_Name + ' LIKE ''%'+#SearchText+'%'' OR '
FROM INFORMATION_SCHEMA.Columns C
WHERE T.TABLE_NAME = C.TABLE_NAME
AND C.DATA_TYPE IN ('nvarchar','varchar')
FOR XML PATH(''))
FROM INFORMATION_SCHEMA.Tables T
DELETE FROM #Tables WHERE ColumnNamesCSVLike IS NULL
INSERT INTO #Tables (N, TableName, ColumnNamesCSVLike)
SELECT ROW_NUMBER() OVER(ORDER BY TableName), TableName, ColumnNamesCSVLike
FROM #Tables
DELETE FROM #Tables WHERE N IS NULL
UPDATE #Tables
SET ColumnNamesCSVLike = SUBSTRING(ColumnNamesCSVLike, 0, LEN(ColumnNamesCSVLike)-2)
UPDATE #Tables SET LIKESQL = 'SELECT * FROM ['+TableName+'] WHERE '+ColumnNamesCSVLike
DECLARE #C INT,
#I INT,
#LIKESQL VARCHAR(4000)
SELECT #I = 1,
#C = COUNT(1)
FROM #Tables
WHILE #I <= #C BEGIN
SELECT #LIKESQL = LIKESQL FROM #Tables WHERE N = #I
SET #I = #I +1
EXEC(#LIKESQL)
END
#NLwino, yery good query with a few errors for keyword usage. I had to modify it a little to wrap the keywords with [ ] and also look char and ntext columns.
DECLARE #searchstring NVARCHAR(255)
SET #searchstring = '%WDB1014%'
DECLARE #sql NVARCHAR(max)
SELECT #sql = STUFF((
SELECT ' UNION ALL SELECT ''' + TABLE_NAME + ''' AS tbl, ''' + COLUMN_NAME + ''' AS col, [' + COLUMN_NAME + '] AS val' +
' FROM ' + TABLE_SCHEMA + '.[' + TABLE_NAME +
'] WHERE [' + COLUMN_NAME + '] LIKE ''' + #searchstring + ''''
FROM INFORMATION_SCHEMA.COLUMNS
WHERE DATA_TYPE in ('nvarchar', 'varchar', 'char', 'ntext')
FOR XML PATH('')
) ,1, 11, '')
Exec (#sql)
I ran it on 2.5 GB database and it came back in 51 seconds
I think this can be an easiest way to find a string in all rows of your database -without using cursors and FOR XML-.
CREATE PROCEDURE SPFindAll (#find VARCHAR(max) = '')
AS
BEGIN
SET NOCOUNT ON;
--
DECLARE #query VARCHAR(max) = ''
SELECT #query = #query +
CASE
WHEN #query = '' THEN ''
ELSE ' UNION ALL '
END +
'SELECT ''' + s.name + ''' As schemaName, ''' + t.name + ''' As tableName, ''' + c.name + ''' As ColumnName, [' + c.name + '] COLLATE DATABASE_DEFAULT As [Data] FROM [' + s.name + '].[' + t.name + '] WHERE [' + c.name + '] Like ''%' + #find + '%'''
FROM
sys.schemas s
INNER JOIN
sys.tables t ON s.[schema_id] = t.[schema_id]
INNER JOIN
sys.columns c ON t.[object_id] = c.[object_id]
INNER JOIN
sys.types ty ON c.user_type_id = ty.user_type_id
WHERE
ty.name LIKE '%char'
EXEC(#query)
END
By creating this stored procedure you can run it for any string you want to find like this:
EXEC SPFindAll 'Hello World'
The result will be like this:
schemaName | tableName | columnName | Data
-----------+-----------+------------+-----------------------
schema1 | Table1 | Column1 | Hello World
schema1 | Table1 | Column1 | Hello World!
schema1 | Table2 | Column1 | I say "Hello World".
schema1 | Table2 | Column2 | Hello World
This uses no cursors or anything like that, just one dynamic query.
Also note that this uses LIKE. Since that happened to be what I needed. It works for all schemas, all tables and only query's those columns that are NVARCHAR or VARCHAR even if they have UDDT.
DECLARE #searchstring NVARCHAR(255)
SET #searchstring = '%searchstring%'
DECLARE #sql NVARCHAR(max)
SELECT #sql = STUFF((
SELECT ' UNION ALL SELECT ''' + TABLE_NAME + ''' AS tablename, ''' + COLUMN_NAME + ''' AS columnname, ' + COLUMN_NAME + ' AS valuename' +
' FROM ' + TABLE_SCHEMA + '.' + TABLE_NAME +
' WHERE ' + COLUMN_NAME + ' LIKE ''' + #searchstring + ''''
FROM INFORMATION_SCHEMA.COLUMNS
WHERE DATA_TYPE in ('nvarchar', 'varchar')
FOR XML PATH('')
) ,1, 11, '')
EXEC(#sql)
The output gives you the table, column and value. Time to execute on a small database was ~3 seconds, had about 3000 results.
/*
This procedure is for finding any string or date in all tables
if search string is date, its format should be yyyy-MM-dd
eg. 2011-07-05
*/
-- ================================================
-- Exec SearchInTables 'f6f56934-a5d4-4967-80a1-1a2223b9c7b1'
-- ================================================
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
-- =============================================
-- Author: <Joshy,,Name>
-- Create date: <Create Date,,>
-- Description: <Description,,>
-- =============================================
ALTER PROCEDURE SearchInTables
#myValue nvarchar(1000)
AS
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;
-- Insert statements for procedure here
DECLARE #searchsql nvarchar(max)
DECLARE #table_name nvarchar(1000)
DECLARE #Schema_name nvarchar(1000)
DECLARE #ParmDefinition nvarchar(500)
DECLARE #XMLIn nvarchar(max)
SET #ParmDefinition = N'#XMLOut varchar(max) OUTPUT'
SELECT A.name,b.name
FROM sys.tables A
INNER JOIN sys.schemas B ON A.schema_id=B.schema_id
WHERE A.name like 'tbl_Tax_Sections'
DECLARE tables_cur CURSOR FOR
SELECT A.name,b.name FOM sys.tables A
INNER JOIN sys.schemas B ON A.schema_id=B.schema_id
WHERE A.type = 'U'
OPEN tables_cur
FETCH NEXT FROM tables_cur INTO #table_name , #Schema_name
WHILE (##FETCH_STATUS = 0)
BEGIN
SET #searchsql ='SELECT #XMLOut=(SELECT PATINDEX(''%'+ #myValue+ '%'''
SET #searchsql =#searchsql + ', (SELECT * FROM '+#Schema_name+'.'+#table_name+' FOR XML AUTO) ))'
--print #searchsql
EXEC sp_executesql #searchsql, #ParmDefinition, #XMLOut=#XMLIn OUTPUT
--print #XMLIn
IF #XMLIn <> 0 PRINT #Schema_name+'.'+#table_name
FETCH NEXT FROM tables_cur INTO #table_name , #Schema_name
END
CLOSE tables_cur
DEALLOCATE tables_cur
RETURN
END
GO
To "find where the data I get comes from", you can start SQL Profiler, start your report or application, and you will see all the queries issued against your database.
Or, you can use my query here, should be simpler then having to create sProcs for each DB you want to search: FullParam SQL Blog
/* Reto Egeter, fullparam.wordpress.com */
DECLARE #SearchStrTableName nvarchar(255), #SearchStrColumnName nvarchar(255), #SearchStrColumnValue nvarchar(255), #SearchStrInXML bit, #FullRowResult bit, #FullRowResultRows int
SET #SearchStrColumnValue = '%searchthis%' /* use LIKE syntax */
SET #FullRowResult = 1
SET #FullRowResultRows = 3
SET #SearchStrTableName = NULL /* NULL for all tables, uses LIKE syntax */
SET #SearchStrColumnName = NULL /* NULL for all columns, uses LIKE syntax */
SET #SearchStrInXML = 0 /* Searching XML data may be slow */
IF OBJECT_ID('tempdb..#Results') IS NOT NULL DROP TABLE #Results
CREATE TABLE #Results (TableName nvarchar(128), ColumnName nvarchar(128), ColumnValue nvarchar(max),ColumnType nvarchar(20))
SET NOCOUNT ON
DECLARE #TableName nvarchar(256) = '',#ColumnName nvarchar(128),#ColumnType nvarchar(20), #QuotedSearchStrColumnValue nvarchar(110), #QuotedSearchStrColumnName nvarchar(110)
SET #QuotedSearchStrColumnValue = QUOTENAME(#SearchStrColumnValue,'''')
DECLARE #ColumnNameTable TABLE (COLUMN_NAME nvarchar(128),DATA_TYPE nvarchar(20))
WHILE #TableName IS NOT NULL
BEGIN
SET #TableName =
(
SELECT MIN(QUOTENAME(TABLE_SCHEMA) + '.' + QUOTENAME(TABLE_NAME))
FROM INFORMATION_SCHEMA.TABLES
WHERE TABLE_TYPE = 'BASE TABLE'
AND TABLE_NAME LIKE COALESCE(#SearchStrTableName,TABLE_NAME)
AND QUOTENAME(TABLE_SCHEMA) + '.' + QUOTENAME(TABLE_NAME) > #TableName
AND OBJECTPROPERTY(OBJECT_ID(QUOTENAME(TABLE_SCHEMA) + '.' + QUOTENAME(TABLE_NAME)), 'IsMSShipped') = 0
)
IF #TableName IS NOT NULL
BEGIN
DECLARE #sql VARCHAR(MAX)
SET #sql = 'SELECT QUOTENAME(COLUMN_NAME),DATA_TYPE
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_SCHEMA = PARSENAME(''' + #TableName + ''', 2)
AND TABLE_NAME = PARSENAME(''' + #TableName + ''', 1)
AND DATA_TYPE IN (' + CASE WHEN ISNUMERIC(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(#SearchStrColumnValue,'%',''),'_',''),'[',''),']',''),'-','')) = 1 THEN '''tinyint'',''int'',''smallint'',''bigint'',''numeric'',''decimal'',''smallmoney'',''money'',' ELSE '' END + '''char'',''varchar'',''nchar'',''nvarchar'',''timestamp'',''uniqueidentifier''' + CASE #SearchStrInXML WHEN 1 THEN ',''xml''' ELSE '' END + ')
AND COLUMN_NAME LIKE COALESCE(' + CASE WHEN #SearchStrColumnName IS NULL THEN 'NULL' ELSE '''' + #SearchStrColumnName + '''' END + ',COLUMN_NAME)'
INSERT INTO #ColumnNameTable
EXEC (#sql)
WHILE EXISTS (SELECT TOP 1 COLUMN_NAME FROM #ColumnNameTable)
BEGIN
PRINT #ColumnName
SELECT TOP 1 #ColumnName = COLUMN_NAME,#ColumnType = DATA_TYPE FROM #ColumnNameTable
SET #sql = 'SELECT ''' + #TableName + ''',''' + #ColumnName + ''',' + CASE #ColumnType WHEN 'xml' THEN 'LEFT(CAST(' + #ColumnName + ' AS nvarchar(MAX)), 4096),'''
WHEN 'timestamp' THEN 'master.dbo.fn_varbintohexstr('+ #ColumnName + '),'''
ELSE 'LEFT(' + #ColumnName + ', 4096),''' END + #ColumnType + '''
FROM ' + #TableName + ' (NOLOCK) ' +
' WHERE ' + CASE #ColumnType WHEN 'xml' THEN 'CAST(' + #ColumnName + ' AS nvarchar(MAX))'
WHEN 'timestamp' THEN 'master.dbo.fn_varbintohexstr('+ #ColumnName + ')'
ELSE #ColumnName END + ' LIKE ' + #QuotedSearchStrColumnValue
INSERT INTO #Results
EXEC(#sql)
IF ##ROWCOUNT > 0 IF #FullRowResult = 1
BEGIN
SET #sql = 'SELECT TOP ' + CAST(#FullRowResultRows AS VARCHAR(3)) + ' ''' + #TableName + ''' AS [TableFound],''' + #ColumnName + ''' AS [ColumnFound],''FullRow>'' AS [FullRow>],*' +
' FROM ' + #TableName + ' (NOLOCK) ' +
' WHERE ' + CASE #ColumnType WHEN 'xml' THEN 'CAST(' + #ColumnName + ' AS nvarchar(MAX))'
WHEN 'timestamp' THEN 'master.dbo.fn_varbintohexstr('+ #ColumnName + ')'
ELSE #ColumnName END + ' LIKE ' + #QuotedSearchStrColumnValue
EXEC(#sql)
END
DELETE FROM #ColumnNameTable WHERE COLUMN_NAME = #ColumnName
END
END
END
SET NOCOUNT OFF
SELECT TableName, ColumnName, ColumnValue, ColumnType, COUNT(*) AS Count FROM #Results
GROUP BY TableName, ColumnName, ColumnValue, ColumnType
This query can do the thing for you.
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 ss.name +'.'+ so.name [name], object_id FROM sys.objects so INNER JOIN sys.schemas ss ON so.schema_id = ss.schema_id 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, 99)
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