Compare 2 rows in MS SQL and get the columns that differ - sql-server

i have searched this one out for a while, but just don't know if there is a "silver bullet" solution to what I'm looking to do. I have a table in my DB (for the sake of this discussion the actual columns are irrelevant). I want to be able to look at 2 rows from the same table and get a list of columns that are different between the 2.
I know I could write a whole bunch of TSQL to make this happen for a specific table, but I was hoping there was a built in function in SQL Server (I'm running 2008 R2) that could do this.
I know there are simple functions like CHECKSUM that will tell me if 2 rows are different, but I need the specifics of which columns are different.
Preferably I would like to make it into a UDF and pass the table name, and primary keys of the 2 rows I want compared.
Any Thoughts or Suggestions?
--EDIT-- Here is the solution I came up with:
Well, It is certainly not the most elegant solution...but it will work in a pinch.
CREATE PROCEDURE sp_Compare_Table_Rows
(
#TablePK varchar(1000), -- The Name of the Primary Key in that Table
#TableName varchar(1000), -- The Name of the Table
#PK1 int, -- The ID of the 1st table
#PK2 int -- The ID of the 2nd table
)
AS
DECLARE #Holder table
(
Column_Name varchar(250),
Different bit
)
INSERT INTO #Holder(Column_Name,Different)
select
COLUMN_NAME,0
from
LPS_DEV.INFORMATION_SCHEMA.COLUMNS
WHERE
TABLE_NAME = #TableName
and ORDINAL_POSITION >1
DECLARE #LoopedColumnName varchar(250)
DECLARE #DynamicQuery nvarchar(max)
DECLARE #ORD1 int
DECLARE #ORD2 int
SET #DynamicQuery = ''
SET #LoopedColumnName = ''
SET #ORD1 = 0
SET #ORD2 = 0
DECLARE MYCUR CURSOR FOR SELECT Column_Name FROM #Holder
OPEN MYCUR
FETCH NEXT FROM MYCUR INTO #LoopedColumnName
WHILE ##FETCH_STATUS = 0
BEGIN
SET #DynamicQuery = 'SELECT #Outer= CHECKSUM(' + #LoopedColumnName + ') FROM ' + #TableName + ' WHERE ' + #TablePK + ' = ' + CONVERT(varchar(100),#PK1)
exec sp_executesql #DynamicQuery, N'#Outer int output',#ORD1 out
SET #DynamicQuery = 'SELECT #Outer= CHECKSUM(' + #LoopedColumnName + ') FROM ' + #TableName + ' WHERE ' + #TablePK + ' = ' + CONVERT(varchar(100),#PK2)
exec sp_executesql #DynamicQuery, N'#Outer int output',#ORD2 out
IF #ORD1 <> #ORD2
BEGIN
UPDATE #Holder SET Different = 1 WHERE Column_Name = #LoopedColumnName
END
FETCH NEXT FROM MYCUR INTO #LoopedColumnName
END
CLOSE MYCUR
DEALLOCATE MYCUR
select * from #Holder

John, you can use something like this. This will display the column names -
Set the #tablename and #whereclause.
declare #tablename varchar(1000),
#cols varchar(max),
#sqlstmt nvarchar(max),
#whereclause nvarchar(max);
set #tablename = 'sometable';
set #whereclause = ' where
a.col1 = ''SOMEOTHERVALUE'' and a.datecol2 = ''19910101'' and
b.col2 = ''SOMEVALUE'' and b.datecol2 = ''19910101''
'
select #cols = stuff((
select ', case when a.' + c.name + ' = b.' + c.name
+ ' then '''' else ''' + c.name + ''' end'
from sys.columns c
inner join sys.tables t on c.object_id = t.object_id
where t.name = #tablename
for xml path ('')), 1, 1, '')
set #sqlstmt = 'select ' + #cols + ' from ' + #tablename
+ ' a, ' + #tablename + ' b ' + #whereclause
exec sp_executesql #sqlstmt

I did some enhancements on Sriram answer, here is the new script:
declare #tablename nvarchar(MAX),
#cols varchar(max) = '',
#sqlstmt nvarchar(max) = 'DECLARE #T AS TABLE (ColumnName NVARCHAR(MAX), Value NVARCHAR(MAX), Value2 NVARCHAR(MAX))',
#whereclause nvarchar(max) = '';
set #tablename = 'TABLE_NAME';
set #whereclause = ' where a.FIRST_ROW_ID = ''NUMBER'' and b.SECOND_ROW_ID = ''NUMBER'''
select #cols = (
select ' INSERT INTO #T SELECT ''' + c.name + ''', cast(a.' + c.name + ' as nvarchar(max)), cast(b.' + c.name + ' as nvarchar(max)) from ' + #tablename + ' a, ' + #tablename + ' b ' + #whereclause + ' AND cast(a.' + c.name + ' as nvarchar(max)) != cast(b.' + c.name + ' as nvarchar(max))'
from sys.columns c
inner join sys.tables t on c.object_id = t.object_id
where t.name = #tablename
for xml path (''))
set #sqlstmt += #cols + ' SELECT * FROM #T'
exec sp_executesql #sqlstmt
You need to replace 'TABLE_NAME' with your table and change the where clause variable.
The result will be like this:
ColumnName | Value | Value2
----------------------------
Id | 1 | 2
Name | Name 1 | Name 2

I have done further enhancement to Sriram Chitturi and Mohamed Noor's answer and also handled datetime comparison
ALTER PROC [dbo].[IdentifyNotMatchingColumnDataBetween2Rows] (
#table_name VARCHAR(300) = 'TableName'
,#excluded_columns VARCHAR(300) = 'Id,UpdateTimeStamp,InsertTimeStamp,IsDuplicate,NotMatchingColumns'
,#compare_row_id_1 INT = 1732340
,#compare_row_id_2 INT = 1736803
)
AS
/*
EXEC [dbo].[IdentifyNotMatchingColumnDataBetween2Rows]
*/
BEGIN
SET NOCOUNT ON;
DECLARE #cols VARCHAR(max) = ''
DECLARE #sqlstmt NVARCHAR(max) = 'DECLARE #T AS TABLE (ColumnName VARCHAR(300), Value NVARCHAR(MAX), Value2 NVARCHAR(MAX))'
DECLARE #where_clause NVARCHAR(max) = ' WHERE a.Id = ''' + CAST(#compare_row_id_1 as varchar(20)) + ''' and b.Id = ''' + CAST(#compare_row_id_2 as varchar(20)) + ''''
SELECT #cols = (
SELECT CASE
WHEN c.system_type_id = 106 --DECIMAL
OR c.system_type_id = 56 --INT
OR c.system_type_id = 48 --TINYINT
OR c.system_type_id = 52 --SMALLINT
OR c.system_type_id = 127 --BIGINT
OR c.system_type_id = 62 --FLOAT
OR c.system_type_id = 108 --NUMERIC
THEN ' INSERT INTO #T SELECT ''[' + c.name + ']'', CAST(a.[' + c.name + '] AS NVARCHAR(MAX)), CAST(b.[' + c.name + '] AS NVARCHAR(MAX)) FROM [' + #table_name + '] a WITH(NOLOCK) , [' + #table_name + '] b WITH(NOLOCK) ' + #where_clause + ' AND CAST(ISNULL(a.[' + c.name + '],' + '-1' + ') AS NVARCHAR(MAX)) != CAST(ISNULL(b.[' + c.name + '],' + '-1' + ') AS NVARCHAR(MAX))'
WHEN c.system_type_id IN (61,42) -- DATETIME / DATETIME2
THEN ' INSERT INTO #T SELECT ''[' + c.name + ']'', FORMAT(a.[' + c.name + '] ,''yyyyMMddHHmmssffff''), FORMAT(b.[' + c.name + '] ,''yyyyMMddHHmmssffff'') FROM [' + #table_name + '] a WITH(NOLOCK) , [' + #table_name + '] b WITH(NOLOCK) ' + #where_clause + ' AND FORMAT(ISNULL(a.[' + c.name + '],' + '''' + '1900-01-01' + '''' + ') ,''yyyyMMddHHmmssffff'') != FORMAT(ISNULL(b.[' + c.name + '],' + '''' + '1900-01-01' + '''' + ') ,''yyyyMMddHHmmssffff'')'
WHEN c.system_type_id = 58 --SMALLDATETIME
THEN ' INSERT INTO #T SELECT ''[' + c.name + ']'', FORMAT(a.[' + c.name + '] ,''yyyyMMddHHmmss''), FORMAT(b.[' + c.name + '] ,''yyyyMMddHHmmss'') FROM [' + #table_name + '] a WITH(NOLOCK) , [' + #table_name + '] b WITH(NOLOCK) ' + #where_clause + ' AND FORMAT(ISNULL(a.[' + c.name + '],' + '''' + '1900-01-01' + '''' + ') ,''yyyyMMddHHmmss'') != FORMAT(ISNULL(b.[' + c.name + '],' + '''' + '1900-01-01' + '''' + ') ,''yyyyMMddHHmmss'')'
ELSE
' INSERT INTO #T SELECT ''[' + c.name + ']'', CAST(a.[' + c.name + '] AS NVARCHAR(MAX)), CAST(b.[' + c.name + '] AS NVARCHAR(MAX)) FROM [' + #table_name + '] a WITH(NOLOCK) , [' + #table_name + '] b WITH(NOLOCK) ' + #where_clause + ' AND CAST(ISNULL(a.[' + c.name + '],' + '''' + '''' + ') AS NVARCHAR(MAX)) != CAST(ISNULL(b.[' + c.name + '],' + '''' + '''' + ') AS NVARCHAR(MAX))'
END
FROM sys.columns c
INNER JOIN sys.tables t ON c.object_id = t.object_id
WHERE t.name = #table_name
AND c.name NOT IN (
SELECT items
FROM dbo.Split(#excluded_columns, ',')
)
FOR XML path('')
)
SET #sqlstmt += #cols + ' SELECT * FROM #T';
--PRINT #sqlstmt;
EXEC sp_executesql #sqlstmt
END
To Execute
EXECUTE dbo.IdentifyNotMatchingColumnDataBetween2Rows 'TableName','Id,UpdateTimeStamp,InsertTimeStamp,Last Checked,IsDuplicate,NotMatchingColumns,',#row_id_1,#row_id_2;

Related

Microsoft SQL Server : find & UPDATE exact value in hall database even if it's PRIMARY

I want to change a specific value at unknown table or column. I reached to the code helped me to search it. I found that at some tables, it's the primary column.
I must do this job because I have a lot of values that need to be changed.
I tried to do the code but I got lot of errors:
Invalid column name 'TableNameA'.
Invalid column name 'ColumnNameA'.
Hope get help as I'm still new for SQL.
What should I do?
DECLARE #SearchStrTableName nvarchar(255), #SearchStrColumnName nvarchar(255), #SearchStrColumnValue nvarchar(255), #SearchStrInXML bit, #FullRowResult bit, #FullRowResultRows int
SET #SearchStrColumnValue = '4523'
Declare #NewValueInt int = 4195403
Declare #NewValueVarChar nvarchar(20) = '4194523'
/* 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)
DECLARE #sqlU VARCHAR(MAX)
Declare #sqlN VARCHAR(MAX)
SET #sqlU = N'UPDATE ' + quotename(#SearchStrTableName) + ' SET ' +quotename(#SearchStrColumnName)+ ' = ''' +#NewValueVarChar+ ''' WHERE ' +quotename(#SearchStrColumnName)+ ' = ''' + #SearchStrColumnValue + '''';
EXEC (#sqlU)
SET #sqlN = N'Update ' + quotename(#SearchStrTableName) + ' SET '+ quotename(#SearchStrColumnName) +'=''' +#NewValueVarChar+ '''where'+ quotename(#SearchStrColumnName) + '='+ #SearchStrColumnValue
EXEC (#sqlN)
END
DELETE FROM #ColumnNameTable WHERE COLUMN_NAME = #ColumnName
END
END
END
SET NOCOUNT OFF
IF OBJECT_ID('tempdb..#Abd_tmptbl') IS NOT NULL DROP TABLE #Abd_tmptbl
CREATE TABLE #Abd_tmptbl (TableNameA nvarchar(128), ColumnNameA nvarchar(128), ColumnValueA nvarchar(max),ColumnTypeA nvarchar(20), Count int)
INSERT INTO #Abd_tmptbl
SELECT TableName, ColumnName, ColumnValue, ColumnType, COUNT(*) AS Count FROM #Results
GROUP BY TableName, ColumnName, ColumnValue, ColumnType
DECLARE #Tableee VARCHAR(20), #Columnee varchar(20), #Constraint varchar(20)
DECLARE #items TABLE(tabl int, clmn int)
Create Table #PK_tbl (PK_Col varchar (10))
WHILE EXISTS (select TOP 1 TableNameA FROM #Abd_tmptbl)
BEGIN
SELECT TOP 1 #Tableee = TableNameA, #Columnee = ColumnNameA
------------ GET All PKs of the Table ---------------------
DECLARE #PK_sql varchar(max) = N'INSERT INTO #PK_tbl(PK_Col)
(SELECT Col.Column_Name from INFORMATION_SCHEMA.TABLE_CONSTRAINTS Tab, 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 = ' + #Tableee +')'
EXEC (#PK_sql)
------------------------------------------------------------
------------ GET CONTRAINT Name ----------------------------
SET #Constraint = N'SELECT name FROM sys.key_constraints WHERE type = "PK" AND OBJECT_NAME(parent_object_id) = ' + #Columnee
------------------------------------------------------------
------------ RELEASE Table From CONSTRAINTS ----------------
DECLARE #REL_tbl VARCHAR(max) = N'ALTER TABLE' + #Tableee +'DROP CONSTRAINT'+ #Constraint
EXEC (#REL_tbl)
------------------------------------------------------------
DECLARE #Update_tbl VARCHAR(max) = N'UPDATE '+ #Tableee + 'SET ' + #Columnee + '=' + #NewValueInt+ ' WHERE' + #Columnee + '=' + #SearchStrColumnValue
EXEC (#Update_tbl)
DECLARE #Sealing_tbl VARCHAR(max) = N'ALTER TABLE' + #Tableee + 'ADD CONSTRAINT' + #Constraint + 'PRIMARY KEY CLUSTERED (SELECT * FROM #PK_tbl)'
EXEC (#Update_tbl)
END

Update/ replace value of extended property using T-SQL

I have around 500 columns and I want to update their extended property value using T-SQL. Basically value has | (pipe) in it and I want to replace all | with CHAR(13) + CHAR(10).
For testing I'm trying to update one value using below code and I'm getting this error
Ad hoc updates to system catalogs are not allowed.
UPDATE p
SET p.value = REPLACE(p.value, '|', CHAR(13) + CHAR(10))
FROM sys.tables AS tbl
INNER JOIN sys.all_columns AS clmns
ON clmns.object_id = tbl.object_id
INNER JOIN sys.extended_properties AS p
ON p.major_id = tbl.object_id
AND p.minor_id = clmns.column_id
AND p.class = 1
WHERE SCHEMA_NAME(tbl.schema_id) = 'dbo'
AND tbl.name = 'ACXM_HHLD'
AND clmns.name = 'Business_Owner';
That was trickier as I thought with NVARCHAR(MAX) that cannot be converted into SQL_VARIANT and stored procedures that don't accept inline CAST expressions...
But this here should do the trick, replacing all | in all column descriptions through CrLf.
DECLARE #TSQL NVARCHAR(MAX) = 'DECLARE #Text AS NVARCHAR(4000);' + CHAR(13) + CHAR(10) + 'DECLARE #Variant AS SQL_VARIANT;' + CHAR(13) + CHAR(10);
WITH Description ([Schema], [Table], [Column], [Text]) AS (
SELECT SCHEMA_NAME(schema_id), tbl.name, clmns.name, CAST(p.value AS NVARCHAR(MAX))
FROM sys.tables AS tbl
INNER JOIN sys.all_columns AS clmns ON clmns.object_id = tbl.object_id
INNER JOIN sys.extended_properties AS p ON p.major_id = tbl.object_id AND p.minor_id = clmns.column_id AND p.Name = 'MS_Description' AND p.class = 1
)
SELECT #TSQL = #TSQL +
N'SET #Text = ''' + REPLACE(REPLACE([Text], '''', ''''''), '|', CHAR(13) + CHAR(10)) + ''';' + CHAR(13) + CHAR(10) +
N'SET #Variant = #Text;' + CHAR(13) + CHAR(10) +
N'EXEC sp_updateextendedproperty N''MS_Description'', #Variant, N''SCHEMA'', ''' + REPLACE([Schema], '''', '''''') + ''', N''TABLE'', ''' + REPLACE([Table], '''', '''''') + ''', N''COLUMN'', ''' + REPLACE([Column], '''', '''''') + '''' + CHAR(13) + CHAR(10)
FROM Description
EXEC sp_executesql #TSQL

How to run a .sql file using bcp in SQL Server

I am new to handling SQL Server bulk export. I have a batch file in which I have written some code to execute specific .sql files at regular intervals and save the output into an excel sheet. I have done this using sqlcmd. I want to use bcp to do the same. Any help on this issue is much appreciated.
use -s "|" with sqlcmd. That should allow you to out-put the data with fields separated by a tab.
-s is for column separator.
See sqlcmd Utility
Hafsa Mushtaq.
The best option is powershell - you can use this awesome dbatools function to Import your data https://github.com/sqlcollaborative/dbatools/blob/development/functions/Import-DbaCsvToSql.ps1 and my script to Export https://github.com/ktaranov/sqlserver-kit/blob/master/PowerShell/Export-SQLTableToCSV.ps1
Or you can use dynamic sql to generate all statements and then execute it.
All stored procedures below needed to solve some limitation of bcp and BULK INSERT in SQL Server - bcp can not create files with header and BULK INSERT can not import in tables with IDENTITY column.
To unload all tables to csv using bcp utility and my stored procedures usp_bcpTableUnload and usp_PrintString:
DECLARE #tsqlCommand NVARCHAR(MAX) = '';
DECLARE #path NVARCHAR(900) = 'd:\111\NIIGAZ\333\';
DECLARE #databaseName SYSNAME = 'NIIGAZ';
DECLARE #exludeColumns NVARCHAR(MAX) = ''; -- '[CreatedDate],[ModifiedDate],[UserID]';
DECLARE #codePage NVARCHAR(10) ='C65001'; -- '1251'
DECLARE #crlf NVARCHAR(10) = CHAR(13);
DECLARE #debug BIT = 1;
IF #debug = 0 SET NOCOUNT ON;
SELECT #tsqlCommand = #tsqlCommand + 'EXECUTE dbo.usp_bcpTableUnload #databaseName = ''' + #databaseName + ''',' + #crlf +
' #path = ''' + #path + ''',' + #crlf +
' #schemaName = ''' + SCHEMA_NAME(t.[schema_id]) + ''',' + #crlf +
' #tableName = ''' + t.[name] + ''',' + #crlf +
' #excludeColumns = ''' + #exludeColumns + ''',' + #crlf +
' #codePage = ''' + #codePage + ''',' + #crlf +
' #formatFile = ''xml'';' + #crlf
FROM [sys].[tables] t
INNER JOIN [sys].[dm_db_partition_stats] ps
ON ps.[object_id] = t.[object_id]
WHERE [index_id] < 2 -- AND SCHEMA_NAME(t.[schema_id]) IN ()
GROUP BY t.[name]
,t.[schema_id]
HAVING SUM(ps.[row_count]) > 1
--ORDER BY 1, 2 ASC
OPTION (RECOMPILE);
IF #debug = 1
BEGIN
EXEC dbo.usp_PrintString #str = #tsqlCommand;
END;
IF #debug = 0
BEGIN
EXEC sp_executesql #tsqlCommand;
END
And to bulk insert this files in database you can use this code and stored procedure usp_BulkUpload:
DECLARE #debug BIT = 0;
DECLARE #tsqlCommand NVARCHAR(max) = '';
DECLARE #path NVARCHAR(1000) = '$(varPath)txt\'; -- 'd:\NII\SQL\txt\';
DECLARE #ExcludeColumns NVARCHAR(1000) = ''; -- 'CreatedDate,ModifiedDate,UserID';
DECLARE #firstRow INTEGER = 2;
DECLARE #fieldTerminator NVARCHAR(10) = '''|''';
DECLARE #crlf NVARCHAR(10) = CHAR(13);
WITH fk_tables AS (
SELECT s1.name AS from_schema
, o1.name AS from_table
, s2.name AS to_schema
, o2.name AS to_table
FROM sys.foreign_keys fk
INNER JOIN sys.objects o1 ON fk.parent_object_id = o1.object_id
INNER JOIN sys.schemas s1 ON o1.schema_id = s1.schema_id
INNER JOIN sys.objects o2 ON fk.referenced_object_id = o2.object_id
INNER JOIN sys.schemas s2 ON o2.schema_id = s2.schema_id
/*For the purposes of finding dependency hierarchy
we're not worried about self-referencing tables*/
WHERE NOT (s1.name = s2.name
AND o1.name = o2.name
)
)
, ordered_tables AS (
SELECT s.name AS schemaName
, t.name AS tableName
, 0 AS table_level
FROM sys.tables AS t
INNER JOIN sys.schemas s ON t.schema_id = s.schema_id
LEFT JOIN fk_tables fk ON s.name = fk.from_schema
AND t.name = fk.from_table
WHERE fk.from_schema IS NULL
UNION ALL
SELECT fk.from_schema
,fk.from_table
,ot.table_level + 1
FROM fk_tables fk
INNER JOIN ordered_tables ot ON fk.to_schema = ot.schemaName
AND fk.to_table = ot.tableName
)
,final AS (
SELECT DISTINCT ot.schemaName
,ot.tableName
,ot.table_level
FROM ordered_tables ot
INNER JOIN (
SELECT schemaName
,tableName
,MAX(table_level) maxLevel
FROM ordered_tables
GROUP BY schemaName
,tableName
) mx ON ot.schemaName = mx.schemaName
AND ot.tableName = mx.tableName
AND mx.maxLevel = ot.table_level
)
SELECT #tsqlCommand = #tsqlCommand +
'EXECUTE dbo.usp_BulkUpload #path = ''' + #path + ''', ' + #crlf +
' #fileName = ''' + QUOTENAME(final.schemaName) + '.' + QUOTENAME(final.tableName) + ''', ' + #crlf +
' #fileExtension = ''txt'', ' + #crlf +
' #databaseName = ''NIIGAZ'', ' + #crlf +
' #schemaName = ''' + final.schemaName + ''', ' + #crlf +
' #tableName = ''' + final.tableName + ''', ' + #crlf +
' #FIRSTROW = ' + CAST(#firstRow AS NVARCHAR) + ',' + #crlf +
' #CODEPAGE = ' + N'65001' + ' ,' + #crlf +
' #useIdentity = ' + CASE WHEN OBJECTPROPERTY(OBJECT_ID(schemaName + '.' + tableName), 'TableHasIdentity') = 1
THEN '1' ELSE '0'
END + ' ,' + #crlf +
' #FIELDTERMINATOR = ' + #fieldTerminator + ',' + #crlf +
' #ROWTERMINATOR = ''' + CASE WHEN final.tableName IN ('PowerPlant', 'Turbine', 'EnergoBusinessArticle') THEN N'0x0a'''
ELSE '\n'''
END + ' ,' + #crlf +
' #excludeColumns = ''' + #ExcludeColumns + ''';' + #crlf
FROM final
WHERE (
final.schemaName NOT IN ('dbo')
AND final.tableName NOT IN (
'ExcludeYourTable'
)
AND final.tableName NOT LIKE '%Temp'
)
OR final.tableName IN ('IncludeYourTable')
OR final.tableName LIKE 'AspNet%'
OR final.tableName LIKE 'Application%'
ORDER BY table_level;
IF #debug = 1 EXECUTE dbo.usp_PrintString #str = #tsqlCommand;
IF #debug = 0 EXECUTE sp_executesql #tsqlCommand;

Please help me fix this stored procedure

When I try to create the following stored procedure, I get this error message:
what am I doing wrong?
Create Procedure uspUpdateWithNewSSN
(
#OldSSN VARCHAR(9)
,#NewSSN VARCHAR(9)
)
AS
SET NOCOUNT ON
BEGIN
If OBJECT_ID(N'NewSSNEXIST') IS NULL
Begin
Create Table NewSSNEXIST
(
NewSSN nvarchar(9)NOT NULL
)
End
Begin
Insert into NewSSNEXIST
Exec uspCheckNewSSN #NewSSN
GO
End
If (select count(*) from NewSSNEXIST)>0
Begin
print 'social security number already used'
Truncate Table NewSSNEXIST;
Return
End
Else
--Begin update ssn
Begin
--Declare #OldSSN VARCHAR(9)
--Declare #NewSSN VARCHAR(9)
Declare #cmd VARCHAR(MAX)
--Set #OldSSN='222334444'
--Set #NewSSN='222334644'
Select #cmd = COALESCE(#cmd,'') +
'
UPDATE [' + TABLE_SCHEMA + '].[' + TABLE_NAME + '] SET [' + Column_Name + '] = ' + #NewSSN + '
WHERE [' + Column_Name + '] = ' + #OldSSN + '
'
From INFORMATION_SCHEMA.COLUMNS
Where Column_Name like 'SSN%'
OR Column_Name LIKE 'ssn%'
OR Column_Name LIKE 'ssn%'
OR Column_Name LIKE '%_ssn%'
OR Column_Name LIKE '_ocsecno'
OR Column_Name LIKE 'Ssn%';
--Select #cmd
EXEC(#cmd)
End
END
GO
Apart from GO key word in your procedure you should also look into your dynamic sql and fix it as follows
Declare #cmd VARCHAR(MAX)
Select #cmd = N' UPDATE ' + QUOTENAME(s.name) + N'.' + QUOTENAME(t.name)
+ N' SET ' + QUOTENAME(c.name) + N' = #NewSSN '
+ N' WHERE ' + QUOTENAME(c.name) + N' = #OldSSN '
From sys.tables t
Inner join sys.columns c ON t.object_id = c.object_id
Inner join sys.schemas s on t.schema_id = s.schema_id
Where c.name like 'SSN%'
OR c.name LIKE 'ssn%'
OR c.name LIKE 'ssn%'
OR c.name LIKE '%_ssn%'
OR c.name LIKE '_ocsecno'
OR c.name LIKE 'Ssn%';
--Select #cmd
EXEC sp_executesql #cmd
,N' #OldSSN VARCHAR(9) ,#NewSSN VARCHAR(9)'
,#OldSSN
,#NewSSN

Find a value anywhere in a database

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

Resources