Sql Server CRUD LOGGER in all tables - sql

A- I need to create a CRUD logger, and its working as well with folowing script, but the problem is that the script does in only one table...
Objective: Install de trigger above in ALL tables, not in ONE TABLE.
I tried to put script 1 into script 2 but no sucess, with so much concatening errors.
Script 1 (its working but in only a table):
DROP TABLE IF EXISTS dbo.audit_trigger;
CREATE TABLE dbo.audit_trigger (
id INT NOT NULL IDENTITY(1,1),
Type CHAR(1),
TableName VARCHAR(128),
PK VARCHAR(1000),
FieldName VARCHAR(128),
OldValue VARCHAR(1000),
NewValue VARCHAR(1000),
UpdateDate datetime,
UserName VARCHAR(128)
);
GO
--deletar trigger
DROP TRIGGER IF EXISTS dbo.tr_UserRole;
GO
CREATE TRIGGER tr_UserRole ON UserRole
FOR
INSERT,
UPDATE,
DELETE
AS
SET NOCOUNT ON;
/*declare all the variables*/
DECLARE #bit INT;
DECLARE #field INT;
DECLARE #maxfield INT;
DECLARE #char INT;
DECLARE #fieldname VARCHAR(128);
DECLARE #TableName VARCHAR(128);
DECLARE #PKCols VARCHAR(1000);
DECLARE #sql VARCHAR(2000);
DECLARE #UpdateDate VARCHAR(21);
DECLARE #UserName VARCHAR(128);
DECLARE #Type CHAR(1);
DECLARE #PKSelect VARCHAR(1000);
/*now set some of these variables*/
SET #TableName = (
SELECT
OBJECT_NAME(parent_object_id)
FROM sys.objects
WHERE
sys.objects.name = OBJECT_NAME(##PROCID)
);
SET #UserName = SYSTEM_USER;
SET #UpdateDate = CONVERT(NVARCHAR(30), GETDATE(), 126);
INSERT INTO audit_trigger (
Type,
TableName,
PK,
FieldName,
OldValue,
NewValue,
UpdateDate,
UserName
) values ( '', '','','','','', #UpdateDate ,'' );
/*Action*/
IF EXISTS (SELECT * FROM INSERTED)
IF EXISTS (SELECT * FROM DELETED)
SET #Type = 'U'
ELSE SET #Type = 'I'
ELSE SET #Type = 'D'
;
/*get list of columns*/
SELECT *
INTO #ins
FROM INSERTED;
SELECT *
INTO #del
FROM DELETED;
/*set #PKCols and #PKSelect via SELECT statement.*/
SELECT #PKCols = /*Get primary key columns for full outer join*/
COALESCE(#PKCols + ' and', ' on')
+ ' i.[' + c.COLUMN_NAME + '] = d.[' + c.COLUMN_NAME + ']'
FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS AS pk
INNER JOIN INFORMATION_SCHEMA.KEY_COLUMN_USAGE AS c ON (
c.TABLE_NAME = pk.TABLE_NAME
AND c.CONSTRAINT_NAME = pk.CONSTRAINT_NAME
)
WHERE pk.TABLE_NAME = #TableName
AND CONSTRAINT_TYPE = 'PRIMARY KEY'
;
SELECT #PKSelect = /*Get primary key select for insert*/
COALESCE(#PKSelect + '+', '')
+ '''<[' + COLUMN_NAME + ']=''+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
SET #field = 0;
SET #maxfield = (
SELECT
MAX(
COLUMNPROPERTY(
OBJECT_ID(TABLE_SCHEMA + '.' + #TableName),
COLUMN_NAME,
'ColumnID'
)
)
FROM INFORMATION_SCHEMA.COLUMNS
WHERE
TABLE_NAME = #TableName
);
WHILE #field < #maxfield
BEGIN
SET #field = (
SELECT
MIN(
COLUMNPROPERTY(
OBJECT_ID(TABLE_SCHEMA + '.' + #TableName),
COLUMN_NAME,
'ColumnID'
)
)
FROM INFORMATION_SCHEMA.COLUMNS
WHERE
TABLE_NAME = #TableName
AND COLUMNPROPERTY(
OBJECT_ID(TABLE_SCHEMA + '.' + #TableName),
COLUMN_NAME,
'ColumnID'
) > #field
);
SET #bit = (#field - 1)% 8 + 1;
SET #bit = POWER(2, #bit - 1);
SET #char = ((#field - 1) / 8) + 1;
IF (
SUBSTRING(COLUMNS_UPDATED(), #char, 1) & #bit > 0
OR #Type IN ('I', 'D')
)
BEGIN
SET #fieldname = (
SELECT
COLUMN_NAME
FROM INFORMATION_SCHEMA.COLUMNS
WHERE
TABLE_NAME = #TableName
AND COLUMNPROPERTY(
OBJECT_ID(TABLE_SCHEMA + '.' + #TableName),
COLUMN_NAME,
'ColumnID'
) = #field
);
SET #sql = ('
INSERT INTO audit_trigger (
Type,
TableName,
PK,
FieldName,
OldValue,
NewValue,
UpdateDate,
UserName
)
SELECT '''
+ #Type + ''','''
+ #TableName + ''','
+ #PKSelect + ','''
+ #fieldname + ''''
+ ',convert(varchar(1000),d.' + #fieldname + ')'
+ ',convert(varchar(1000),i.' + #fieldname + ')'
+ ',''' + #UpdateDate + ''''
+ ',''' + #UserName + '''' +
' FROM #ins AS i FULL OUTER JOIN #del AS d'
+ #PKCols +
' WHERE i.' + #fieldname + ' <> d.' + #fieldname
+ ' or (i.' + #fieldname + ' is null and d.'
+ #fieldname
+ ' is not null)'
+ ' or (i.' + #fieldname + ' is not null and d.'
+ #fieldname
+ ' is null)'
);
EXEC (#sql)
END
END
SET NOCOUNT OFF;
GO
Script 2:
DECLARE #SQL AS NVARCHAR(MAX) = ''
DECLARE cur_trigger CURSOR FOR
SELECT '
CREATE TRIGGER [' + TABLE_SCHEMA + '].[tr' + TABLE_NAME + '_aeae]
ON [' + TABLE_SCHEMA + '].[' + TABLE_NAME + '] FOR INSERT, UPDATE, DELETE AS
BEGIN
script 1 goes here...................................
END
CLOSE cur_trigger
DEALLOCATE cur_trigger
My try:
DECLARE #SQL AS NVARCHAR(MAX) = ''
DECLARE cur_trigger CURSOR FOR
SELECT '
CREATE TRIGGER [' + TABLE_SCHEMA + '].[tr' + TABLE_NAME + '_aeae]
ON [' + TABLE_SCHEMA + '].[' + TABLE_NAME + '] FOR INSERT, UPDATE, DELETE AS
BEGIN
SET NOCOUNT ON;
/*declare all the variables*/
DECLARE #bit INT;
DECLARE #field INT;
DECLARE #maxfield INT;
DECLARE #char INT;
DECLARE #fieldname VARCHAR(128);
DECLARE #TableName VARCHAR(128);
DECLARE #PKCols VARCHAR(1000);
DECLARE #sql VARCHAR(2000);
DECLARE #UpdateDate VARCHAR(21);
DECLARE #UserName VARCHAR(128);
DECLARE #Type CHAR(1);
DECLARE #PKSelect VARCHAR(1000);
DECLARE #OI VARCHAR(50)= '''';
/*now set some of these variables*/
SET #TableName = (
SELECT
OBJECT_NAME(parent_object_id)
FROM sys.objects
WHERE
sys.objects.name = OBJECT_NAME(##PROCID)
);
SET #UserName = SYSTEM_USER;
SET #UpdateDate = CONVERT(NVARCHAR(30), GETDATE(), 126);
INSERT INTO audit_trigger (
Type,
TableName,
PK,
FieldName,
OldValue,
NewValue,
UpdateDate,
UserName
) values ( #OI, #OI,#OI,#OI,#OI,#OI, CONVERT(NVARCHAR(30), GETDATE(), 126) ,#OI );
/*Action*/
IF EXISTS (SELECT * FROM INSERTED)
IF EXISTS (SELECT * FROM DELETED)
SET #Type = ''U''
ELSE SET #Type = ''I''
ELSE SET #Type = ''D'';
/*get list of columns*/
SELECT *
INTO #ins
FROM INSERTED;
SELECT *
INTO #del
FROM DELETED;
SELECT #PKCols =
COALESCE(#PKCols + '' and'', '' on'')
+ '' i.['' + c.COLUMN_NAME + ''] = d.['' + c.COLUMN_NAME + '']''
FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS AS pk
INNER JOIN INFORMATION_SCHEMA.KEY_COLUMN_USAGE AS c ON (
c.TABLE_NAME = pk.TABLE_NAME
AND c.CONSTRAINT_NAME = pk.CONSTRAINT_NAME
)
WHERE pk.TABLE_NAME = #TableName
AND CONSTRAINT_TYPE = ''PRIMARY KEY'';
dificults starts above in concatening....................................................................................
END
'
FROM INFORMATION_SCHEMA.TABLES
WHERE TABLE_TYPE = 'BASE TABLE'
AND TABLE_NAME <> 'audit_trigger'
ORDER BY TABLE_NAME
OPEN cur_trigger
FETCH NEXT FROM cur_trigger INTO #SQL
WHILE ##FETCH_STATUS = 0
BEGIN
EXEC(#SQL)
FETCH NEXT FROM cur_trigger INTO #SQL
END
CLOSE cur_trigger
DEALLOCATE cur_trigger
i tried to put the script 1 into script 2 but happens so much concatening erros

Related

How do I find in which table Data has my given value in SQL

What I need is to find out which tables have certain column data. It doesn't matter which column it belongs in, I just don't know which table to look at since there are a lot of tables.
Please let me know if you have ideas. Thanks.
Note: I should search in XML columns as well.
This is what I have tried. It did not work, please suggest better ideas for me to try.
USE DATABASE_NAME
DECLARE #SearchStr nvarchar(100) = 'SEARCH_TEXT'
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', 'int', 'decimal')
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
I made changes to the code you already had to include the XML datatype and cast the XML into NVARCHAR (MAX) in the WHERE clause and in the table variable.
USE DATABASE_NAME
DECLARE #SearchStr nvarchar(100) = 'SEARCH_TEXT'
DECLARE #Results TABLE (ColumnName nvarchar(370), ColumnValue nvarchar(max))
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', 'int',
'decimal','xml') AND QUOTENAME(COLUMN_NAME) > #ColumnName )
IF #ColumnName IS NOT NULL
BEGIN
INSERT INTO #Results
EXEC
(
'SELECT ''' + #TableName + '.' + #ColumnName + ''','+
'cast('+ #ColumnName+ ' as nvarchar(max))'
+'FROM ' + #TableName + ' (NOLOCK) ' +
' WHERE cast( ' + #ColumnName + ' as nvarchar(max)) LIKE ' + #SearchStr2
)
END
END
END
SELECT ColumnName, ColumnValue FROM #Results

SQL Server : Search for a string across all the databases and list all the databases, tables and corresponding columns

I am wondering if there is a way I can view all the databases and the corresponding tables where a specific string is present in SQL Server 2012.
I was able to search for a string in all the tables in a particular database by using a stored procedure below which I found online. But I would like to search it across all the databases.
CREATE PROC SearchAllTables
(
#SearchStr nvarchar(100)
)
AS
BEGIN
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 DATA_TYPE IN ('char', 'varchar', 'nchar', 'nvarchar', 'int', 'decimal')
AND QUOTENAME(COLUMN_NAME) > #ColumnName
)
IF #ColumnName IS NOT NULL
BEGIN
INSERT INTO #Results
EXEC
(
'SELECT ''' + #TableName + '.' + #ColumnName + ''', LEFT(' + #ColumnName + ', 3630)
FROM ' + #TableName + 'WITH (NOLOCK) ' +
' WHERE ' + #ColumnName + ' LIKE ' + #SearchStr2
)
END
END
END
SELECT ColumnName, ColumnValue FROM #Results
END
And when I execute the below query, it lists all the tables along with the column names.
exec SearchAllTables "B2"
OUTPUT:
ColumnName ColumnValue
[dbo].[msm_temp].[molecule_nm] B2
[dbo].[msm_temp1].[molecule_nm] B2
[dbo].[msm_temp2].[molecule_nm] B2
[dbo].[msm_temp3].[molecule_nm] B2
[dbo].[msm_temp4].[molecule_nm] B2
How do I solve the problem?
You can use this stored procedure with value for search like this :
exec SearchAllDatabases #SearchTerm = '%B2%'
This can help you to search everywhere but if you have too much data in your databases this will take time to execute.
Stored 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
I hope this helps you.

Generate insert statement which has same columns of a table in SQL Server

I have wide table with 100 columns.
I need a SP which takes 100 parameters and then does the insert.
I know how to do this manually. But having the table definition and knowing that SP parameters will have exact same name of the table columns, can you think of a better/faster way to generate this stored procedure?
I use SQL to write it for you. Check it out and let me know if it needs any tweaks or if you have any questions.
IF OBJECT_ID('yourTable') IS NOT NULL
DROP TABLE yourTable;
CREATE TABLE yourTable
(
col1 INT,
col2 VARCHAR(100),
col3 NUMERIC(18,2)
)
DECLARE #InputParams VARCHAR(MAX),
#InsertColumns VARCHAR(MAX),
#InsertParams VARCHAR(MAX);
WITH CTE_columns
AS
(
SELECT COLUMN_NAME,
UPPER(DATA_TYPE) data_type,
'(' + CAST(CHARACTER_MAXIMUM_LENGTH AS VARCHAR(10)) + ')' max_length,
CASE
WHEN DATA_TYPE IN ('Numeric','Decimal') THEN CONCAT('(',NUMERIC_PRECISION,',',NUMERIC_SCALE,')')
END prec_scale
--#InsertColumns = COALESCE(#InsertColumns + ',','') + COLUMN_NAME,
FROM INFORMATION_SCHEMA.COLUMNS A
WHERE TABLE_NAME = 'yourTable'
)
SELECT #InputParams = COALESCE(#InputParams + ',','') + CONCAT('#',column_name,' ',data_type,max_length,prec_scale),
#InsertColumns = COALESCE(#InsertColumns + ',','') + COLUMN_NAME,
#InsertParams = COALESCE(#InsertParams + ',','') + '#'+ COLUMN_NAME
FROM CTE_columns
SELECT
'CREATE PROCEDURE dbo.yourProc ' + #InputParams +
' AS
INSERT INTO yourTable(' + #InsertColumns + ')
VALUES (' + #InsertParams + ');
GO'
Results(Formatting isn't great, but it works):
CREATE PROCEDURE dbo.yourProc #col1 INT,#col2 VARCHAR(100),#col3 NUMERIC(18,2) AS
INSERT INTO yourTable(col1,col2,col3)
VALUES (#col1,#col2,#col3);
GO
For this type of scenario, I like to leverage table types.
First, create the table type:
CREATE TYPE [YourType] AS TABLE (columns...)
In C#, populate a DataTable "template" by running this query (using a DataAdapter):
DECLARE #tt AS [YourType]
SELECT * FROM #tt
Then add a row to the table and cycle through the columns to add the necessary values.
Then pass the datatable as a parameter into your procedure:
CREATE PROCEDURE [YourProc]
#tt [YourType] READONLY
AS
BEGIN
--do stuff
END
An added benefit of this approach is that you can pass multiple records into the procedure with a single call.
You can probably quickly modify this for your needs:
Declare #tableName nvarchar(100) = 'aspnet_Membership'
Declare #objectName nvarchar(100) = 'Membership'
DECLARE #newLineChar AS CHAR(2) = CHAR(13) + CHAR(10)
Declare #columnName nvarchar(50)
Declare #dataType nvarchar(50)
Declare #characterLength int
Declare #isNullableString varchar(3)
Declare #ordinalPosition int
Declare #firstSortOrder smallint
Declare #variableTableCreateCode nvarchar(max) = ''
Declare #variableTableDataTypeCode nvarchar(128)
Declare #variableTableSelectCode001 nvarchar(max) = ''
Declare #variableTableSelectCode002 nvarchar(max) = ''
Declare #varableTableInsertIntoCode nvarchar(max) = ''
Declare tbl_ColumnCursor Cursor For
Select colSchema.COLUMN_NAME, colSchema.DATA_TYPE, colSchema.CHARACTER_MAXIMUM_LENGTH, colSchema.IS_NULLABLE , colSchema.ORDINAL_POSITION , FirstSortOrder = CASE WHEN PrimaryKeyDerived.CONSTRAINT_TYPE IS NOT NULL THEN 1 ELSE 2 END
from INFORMATION_SCHEMA.COLUMNS colSchema
LEFT JOIN
(
SELECT
INFORMATION_SCHEMA.COLUMNS.TABLE_NAME
,INFORMATION_SCHEMA.COLUMNS.COLUMN_NAME
,INFORMATION_SCHEMA.TABLE_CONSTRAINTS.CONSTRAINT_TYPE
FROM INFORMATION_SCHEMA.COLUMNS
LEFT OUTER JOIN information_schema.KEY_COLUMN_USAGE
ON
INFORMATION_SCHEMA.COLUMNS.TABLE_NAME=information_schema.KEY_COLUMN_USAGE.TABLE_NAME
AND INFORMATION_SCHEMA.COLUMNS.COLUMN_NAME=information_schema.KEY_COLUMN_USAGE.COLUMN_NAME
LEFT OUTER JOIN INFORMATION_SCHEMA.TABLE_CONSTRAINTS
ON
information_schema.KEY_COLUMN_USAGE.TABLE_NAME=information_schema.TABLE_CONSTRAINTS.TABLE_NAME
AND information_schema.KEY_COLUMN_USAGE.CONSTRAINT_NAME=information_schema.TABLE_CONSTRAINTS.CONSTRAINT_NAME
WHERE CONSTRAINT_TYPE = 'PRIMARY KEY'
) as PrimaryKeyDerived on colSchema.TABLE_NAME = PrimaryKeyDerived.TABLE_NAME and colSchema.COLUMN_NAME = PrimaryKeyDerived.COLUMN_NAME
where colSchema.TABLE_NAME = #tableName
Order By FirstSortOrder , colSchema.ORDINAL_POSITION
Set #variableTableCreateCode = 'declare #' + #objectName + 'Holder table ( ' + #objectName + 'SurrogateKey int , '
Set #variableTableSelectCode001 = 'INSERT INTO #' + #objectName + 'Holder ( '
Set #variableTableSelectCode002 = ' SELECT '
Set #varableTableInsertIntoCode = 'INSERT INTO '+#tableName+' ( '
Open tbl_ColumnCursor
Fetch Next From tbl_ColumnCursor Into #ColumnName, #dataType, #characterLength, #isNullableString, #ordinalPosition , #firstSortOrder
While ##FETCH_STATUS = 0
Begin
print '/#ColumnName/'
print #ColumnName
print ''
print '/##dataType/'
print #dataType
print ''
print '/###isNullableString/'
print #isNullableString
print ''
Select #variableTableDataTypeCode =
case
when #dataType like '%char%' and #characterLength = -1 Then
#dataType+'(max)'
when #dataType like '%char%' and #characterLength = 1 Then
#dataType+'('+convert(varchar(32), #characterLength)+')'
When (#dataType like '%char%') Or (#dataType = 'xml') Or (#dataType like '%text%') Then
#dataType+'('+convert(varchar(32), #characterLength)+')'
Else #dataType
End
Set #variableTableCreateCode = #variableTableCreateCode + ' [' + #columnName + '] ' + #variableTableDataTypeCode +','
select #variableTableSelectCode002 = #variableTableSelectCode002 + 'T.MyEntity.value(''#' + #columnName + ''', '''+#variableTableDataTypeCode+''') AS ' + #columnName + ','
Fetch Next From tbl_ColumnCursor Into #ColumnName, #dataType, #characterLength , #isNullableString , #ordinalPosition , #firstSortOrder
End
Close tbl_ColumnCursor
Deallocate tbl_ColumnCursor
if(DATALENGTH(#variableTableCreateCode) > 0)
BEGIN
select #variableTableCreateCode = LEFT(#variableTableCreateCode, LEN(#variableTableCreateCode) -1)
END
if(DATALENGTH(#variableTableSelectCode002) > 0)
BEGIN
select #variableTableSelectCode002 = LEFT(#variableTableSelectCode002, LEN(#variableTableSelectCode002) -1)
END
Set #variableTableCreateCode = #variableTableCreateCode + #newLineChar + ' ) '
select #variableTableCreateCode
select #variableTableSelectCode001 = #variableTableSelectCode001 + ( SELECT
MyColumns = STUFF
(
(
SELECT ', [' + r.COLUMN_NAME + ']'
FROM INFORMATION_SCHEMA.COLUMNS AS r
WHERE r.TABLE_NAME = tabs.TABLE_NAME
ORDER BY r.ORDINAL_POSITION
FOR XML PATH(''), TYPE
).value('.[1]','nvarchar(max)'),
1,1,''
)
FROM INFORMATION_SCHEMA.TABLES AS tabs
/* Optional WHERE Clause */
WHERE
tabs.TABLE_NAME = #tableName
)
select #variableTableSelectCode001 = #variableTableSelectCode001 + ' ) '+#newLineChar
select #variableTableSelectCode002 = #variableTableSelectCode002 + ' FROM #xmldata.nodes(''RootElement/' + #tableName + 'Elements/' + #tableName + 'Element'') AS T(MyEntity); '
select #variableTableSelectCode001 + #variableTableSelectCode002
select #varableTableInsertIntoCode = #varableTableInsertIntoCode + ( SELECT
MyColumns = STUFF
(
(
SELECT ', [' + r.COLUMN_NAME + ']'
FROM INFORMATION_SCHEMA.COLUMNS AS r
WHERE r.TABLE_NAME = tabs.TABLE_NAME
ORDER BY r.ORDINAL_POSITION
FOR XML PATH(''), TYPE
).value('.[1]','nvarchar(max)'),
1,1,''
)
FROM INFORMATION_SCHEMA.TABLES AS tabs
WHERE
tabs.TABLE_NAME = #tableName
)
select #varableTableInsertIntoCode = #varableTableInsertIntoCode + ' ) SELECT '
select #varableTableInsertIntoCode = #varableTableInsertIntoCode + ( SELECT
MyColumns = STUFF
(
(
SELECT ', holder.[' + r.COLUMN_NAME + ']'
FROM INFORMATION_SCHEMA.COLUMNS AS r
WHERE r.TABLE_NAME = tabs.TABLE_NAME
ORDER BY r.ORDINAL_POSITION
FOR XML PATH(''), TYPE
).value('.[1]','nvarchar(max)'),
1,1,''
)
FROM INFORMATION_SCHEMA.TABLES AS tabs
WHERE
tabs.TABLE_NAME = #tableName
)
select #varableTableInsertIntoCode = #varableTableInsertIntoCode + ' from #' + #objectName + 'Holder holder where not exists ( select null from ' +#tableName+ ' realTable where realTable.Name = holder.Name and realTable.IsDeleted = holder.IsDeleted ) '
select #varableTableInsertIntoCode
SELECT
tabs.TABLE_NAME,
MyColumns = STUFF
(
(
SELECT ', alias.[' + r.COLUMN_NAME + ']'
FROM INFORMATION_SCHEMA.COLUMNS AS r
WHERE r.TABLE_NAME = tabs.TABLE_NAME
ORDER BY r.ORDINAL_POSITION
FOR XML PATH(''), TYPE
).value('.[1]','nvarchar(max)'),
1,1,''
)
FROM INFORMATION_SCHEMA.TABLES AS tabs
/* Optional WHERE Clause */
WHERE
tabs.TABLE_NAME = #tableName
ORDER BY tabs.TABLE_NAME;

Fire the trigger without primary key

i have a question here. Some of my table does not have any primary key, but my trigger is work based on primary key, is that any solution?
For example:
create trigger tr_tableA on dbo.tableA
after update
as
declare
#bit int,
#field int ,
#maxfield int,
#char int,
#fieldname varchar(128),
#TableName varchar(128),
#PKCols varchar(500),
#sql varchar(2000),
#Type char(1),
#PKSelect varchar(500),
select #TableName = 'tableA'
if exists(select * from inserted)
if exists(select * from deleted)
select #Type = 'U'
else
print('do nothing')
select * into #ins from inserted
select * into #del from deleted
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
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 ('U')
begin
select #fieldname = COLUMN_NAME from INFORMATION_SCHEMA.COLUMNS where TABLE_NAME = #TableName and ORDINAL_POSITION = #field
select #sql = 'insert into tableB (Description, OldValue, NewValue)'
select #sql = #sql + ' select ''' + #fieldname + ''''
select #sql = #sql + ',d.' + #fieldname + ''
select #sql = #sql + ',i.' + #fieldname + ''
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
Some of my table does not have any primary key, but my trigger is work
based on primary key, is that any solution?
Nope... you said it yourself, your trigger is based on primary key.
Any reason you don't have a primary key on a table?

Find a string by searching all tables in SQL Server

Is there any way to search for a string in all tables of a database in SQL Server?
I want to search for string say john. The result should show the tables and their respective row that contain john.
If you are like me and have certain restrictions in a production environment, you may wish to use a table variable instead of temp table, and an ad-hoc query rather than a create procedure.
Of course depending on your sql server instance, it must support table variables.
I also added a USE statement to narrow the search scope
USE DATABASE_NAME
DECLARE #SearchStr nvarchar(100) = 'SEARCH_TEXT'
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', 'int', 'decimal')
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
A bit late but hopefully useful.
Why not try some of the third party tools that can be integrated into SSMS.
I’ve worked with ApexSQL Search (100% free) with good success for both schema and data search and there is also SSMS tools pack that has this feature (not free for SQL 2012 but quite affordable).
Stored procedure above is really great; it’s just that this is way more convenient in my opinion. Also, it would require some slight modifications if you want to search for datetime columns or GUID columns and such…
To update TechDo's answer for SQL server 2012. You need to change: 'FROM ' + #TableName + ' (NOLOCK) ' to FROM ' + #TableName + 'WITH (NOLOCK) ' +
Other wise you will get the following error: Deprecated feature 'Table hint without WITH' is not supported in this version of SQL Server.
Below is the complete updated stored procedure:
CREATE PROC SearchAllTables
(
#SearchStr nvarchar(100)
)
AS
BEGIN
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 DATA_TYPE IN ('char', 'varchar', 'nchar', 'nvarchar', 'int', 'decimal')
AND QUOTENAME(COLUMN_NAME) > #ColumnName
)
IF #ColumnName IS NOT NULL
BEGIN
INSERT INTO #Results
EXEC
(
'SELECT ''' + #TableName + '.' + #ColumnName + ''', LEFT(' + #ColumnName + ', 3630)
FROM ' + #TableName + 'WITH (NOLOCK) ' +
' WHERE ' + #ColumnName + ' LIKE ' + #SearchStr2
)
END
END
END
SELECT ColumnName, ColumnValue FROM #Results
END
A bit late, but you can easily find a string with this query
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)
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
There's no need for nested looping (outer looping through tables and inner looping through all table columns). One can retrieve all (or arbitrary selected/filtered) table-column combinations from INFORMATION_SCHEMA.COLUMNS and in one loop simply pass through (search) all of them:
DECLARE #search VARCHAR(100), #table SYSNAME, #column SYSNAME
DECLARE curTabCol CURSOR FOR
SELECT c.TABLE_SCHEMA + '.' + c.TABLE_NAME, c.COLUMN_NAME
FROM INFORMATION_SCHEMA.COLUMNS c
JOIN INFORMATION_SCHEMA.TABLES t
ON t.TABLE_NAME=c.TABLE_NAME AND t.TABLE_TYPE='BASE TABLE' -- avoid views
WHERE c.DATA_TYPE IN ('varchar','nvarchar') -- searching only in these column types
--AND c.COLUMN_NAME IN ('NAME','DESCRIPTION') -- searching only in these column names
SET #search='john'
OPEN curTabCol
FETCH NEXT FROM curTabCol INTO #table, #column
WHILE (##FETCH_STATUS = 0)
BEGIN
EXECUTE('IF EXISTS
(SELECT * FROM ' + #table + ' WHERE ' + #column + ' = ''' + #search + ''')
PRINT ''' + #table + '.' + #column + '''')
FETCH NEXT FROM curTabCol INTO #table, #column
END
CLOSE curTabCol
DEALLOCATE curTabCol
I have written a SP for the this which returns the search results in form of Table name, the Column names in which the search keyword string was found as well as the searches the corresponding rows as shown in below screen shot.
This might not be the most efficient solution but you can always modify and use it according to your need.
IF OBJECT_ID('sp_KeywordSearch', 'P') IS NOT NULL
DROP PROC sp_KeywordSearch
GO
CREATE PROCEDURE sp_KeywordSearch #KeyWord NVARCHAR(100)
AS
BEGIN
DECLARE #Result TABLE
(TableName NVARCHAR(300),
ColumnName NVARCHAR(MAX))
DECLARE #Sql NVARCHAR(MAX),
#TableName NVARCHAR(300),
#ColumnName NVARCHAR(300),
#Count INT
DECLARE #tableCursor CURSOR
SET #tableCursor = CURSOR LOCAL SCROLL FOR
SELECT N'SELECT #Count = COUNT(1) FROM [dbo].[' + T.TABLE_NAME + '] WITH (NOLOCK) WHERE CAST([' + C.COLUMN_NAME +
'] AS NVARCHAR(MAX)) LIKE ''%' + #KeyWord + N'%''',
T.TABLE_NAME,
C.COLUMN_NAME
FROM INFORMATION_SCHEMA.TABLES AS T WITH (NOLOCK)
INNER JOIN INFORMATION_SCHEMA.COLUMNS AS C WITH (NOLOCK)
ON T.TABLE_SCHEMA = C.TABLE_SCHEMA AND
T.TABLE_NAME = C.TABLE_NAME
WHERE T.TABLE_TYPE = 'BASE TABLE' AND
C.TABLE_SCHEMA = 'dbo' AND
C.DATA_TYPE NOT IN ('image', 'timestamp')
OPEN #tableCursor
FETCH NEXT FROM #tableCursor INTO #Sql, #TableName, #ColumnName
WHILE (##FETCH_STATUS = 0)
BEGIN
SET #Count = 0
EXEC sys.sp_executesql
#Sql,
N'#Count INT OUTPUT',
#Count OUTPUT
IF #Count > 0
BEGIN
INSERT INTO #Result
(TableName, ColumnName)
VALUES (#TableName, #ColumnName)
END
FETCH NEXT FROM #tableCursor INTO #Sql, #TableName, #ColumnName
END
CLOSE #tableCursor
DEALLOCATE #tableCursor
SET #tableCursor = CURSOR LOCAL SCROLL FOR
SELECT SUBSTRING(TB.Sql, 1, LEN(TB.Sql) - 3) AS Sql, TB.TableName, SUBSTRING(TB.Columns, 1, LEN(TB.Columns) - 1) AS Columns
FROM (SELECT R.TableName, (SELECT R2.ColumnName + ', ' FROM #Result AS R2 WHERE R.TableName = R2.TableName FOR XML PATH('')) AS Columns,
'SELECT * FROM ' + R.TableName + ' WITH (NOLOCK) WHERE ' +
(SELECT 'CAST(' + R2.ColumnName + ' AS NVARCHAR(MAX)) LIKE ''%' + #KeyWord + '%'' OR '
FROM #Result AS R2
WHERE R.TableName = R2.TableName
FOR
XML PATH('')) AS Sql
FROM #Result AS R
GROUP BY R.TableName) TB
ORDER BY TB.Sql
OPEN #tableCursor
FETCH NEXT FROM #tableCursor INTO #Sql, #TableName, #ColumnName
WHILE (##FETCH_STATUS = 0)
BEGIN
PRINT #Sql
SELECT #TableName AS [Table],
#ColumnName AS Columns
EXEC(#Sql)
FETCH NEXT FROM #tableCursor INTO #Sql, #TableName, #ColumnName
END
CLOSE #tableCursor
DEALLOCATE #tableCursor
END
There are lots of workable answers already. Just thought I would add one I came up with that has a lot of optional funcionality.
--=======================================================================
-- 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;
*********************************************************************/
Improving the amazing answer from #Brandon, I added type to ntext and xml using castings:
BEGIN TRAN
DECLARE #SearchStr nvarchar(100) = 'SEARCH_TEXT'
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', 'int', 'decimal', 'ntext', 'xml')
AND QUOTENAME(COLUMN_NAME) > #ColumnName
)
IF #ColumnName IS NOT NULL
BEGIN
INSERT INTO #Results
EXEC
(
'SELECT ''' + #TableName + '.' + #ColumnName + ''', LEFT((cast(' + #ColumnName + ' as nvarchar(max))), 3630)
FROM ' + #TableName + ' (NOLOCK) ' +
' WHERE (cast(' + #ColumnName + ' as nvarchar(max))) LIKE ' + #SearchStr2
)
END
END
END
SELECT ColumnName, ColumnValue FROM #Results
ROLLBACK
Not to take away from the excellent answer by #Brandon but the OP requested "The result should show the tables and their respective row". I created a record-level solution based on the original answer from #Brandon that also avoids the use of CURSORs used by others here by simply concatenating all the appropriate columns into one string. (I have the feeling this would perform better but I honestly haven't compared results - feel free to do so and provide feedback here.)
NB I have used the STRING_AGG function to concatenate the columns. If you have an older version of SQL Server you may need to use one of the alternate methods that can be found online.
CREATE PROC [dbo].[SearchAllTablesByRecord]
(
#SearchStr NVARCHAR(100)
)
AS
BEGIN
SET NOCOUNT ON
DECLARE #TableName NVARCHAR(256), #SearchStr2 NVARCHAR(110)
DECLARE #ColumnList NVARCHAR(2048), #ColumnJoin NVARCHAR(2048)
SET #TableName = ''
SET #SearchStr2 = QUOTENAME('%' + #SearchStr + '%','''')
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 QUOTENAME(TABLE_SCHEMA) + '.' + QUOTENAME(TABLE_NAME) > #TableName
AND OBJECTPROPERTY(
OBJECT_ID(
QUOTENAME(TABLE_SCHEMA) + '.' + QUOTENAME(TABLE_NAME)
), 'IsMSShipped'
) = 0
)
PRINT #TableName -- For progress monitoring
SET #ColumnList =
(
SELECT STRING_AGG(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')
)
SET #ColumnJoin = REPLACE(#ColumnList,',','+')
IF #ColumnList <> ''
EXEC
(
'SELECT ''' + #TableName + ''' AS [Table],' + #ColumnList + '
INTO #Results
FROM ' + #TableName + ' (NOLOCK) ' +
' WHERE ' + #ColumnJoin + ' LIKE ' + #SearchStr2 + '
IF ##ROWCOUNT > 0 SELECT * FROM #Results'
)
END
END
This was very helpful. I wanted to import this function to a Postgre SQL database. Thought i would share it with anyone who is interested. Will have them a few hours. Note: this function creates a list of SQL statements that can be copied and executed on the Postgre database. Maybe someone smarter then me can get Postgre to create and execute the statements all in one function.
CREATE OR REPLACE FUNCTION SearchAllTables(_search text) RETURNS TABLE( txt text ) as $funct$
DECLARE __COUNT int;
__SQL text;
BEGIN
EXECUTE 'SELECT COUNT(0) FROM INFORMATION_SCHEMA.COLUMNS
WHERE DATA_TYPE = ''text''
AND table_schema = ''public'' ' INTO __COUNT;
RETURN QUERY
SELECT CASE WHEN ROW_NUMBER() OVER (ORDER BY table_name) < __COUNT THEN
'SELECT ''' || table_name ||'.'|| column_name || ''' AS tbl, "' || column_name || '" AS col FROM "public"."' || "table_name" || '" WHERE "'|| "column_name" || '" ILIKE ''%' || _search || '%'' UNION ALL'
ELSE
'SELECT ''' || table_name ||'.'|| column_name || ''' AS tbl, "' || column_name || '" AS col FROM "public"."' || "table_name" || '" WHERE "'|| "column_name" || '" ILIKE ''%' || _search || '%'''
END AS txt
FROM INFORMATION_SCHEMA.COLUMNS
WHERE DATA_TYPE = 'text'
AND table_schema = 'public';
END
$funct$ LANGUAGE plpgsql;
The answer that was mentioned in this post already several times I have adopted a little bit because I needed to search in only one table too:
(and also made input for the table name a bit more simpler)
ALTER PROC dbo.db_compare_SearchAllTables_sp
(
#SearchStr nvarchar(100),
#TableName nvarchar(256) = ''
)
AS
BEGIN
if PARSENAME(#TableName, 2) is null
set #TableName = 'dbo.' + QUOTENAME(#TableName, '"')
declare #results TABLE(ColumnName nvarchar(370), ColumnValue nvarchar(3630))
SET NOCOUNT ON
DECLARE #ColumnName nvarchar(128) = '', #SearchStr2 nvarchar(110)
SET #SearchStr2 = QUOTENAME('%' + #SearchStr + '%','''')
IF #TableName <> ''
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 + ' WITH (NOLOCK) ' +
' WHERE ' + #ColumnName + ' LIKE ' + #SearchStr2
)
END
END
ELSE
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 + ' WITH (NOLOCK) ' +
' WHERE ' + #ColumnName + ' LIKE ' + #SearchStr2
)
END
END
END
SELECT ColumnName, ColumnValue FROM #results
END
[CREATE PROC SearchAllTables ( #SearchStr nvarchar(100) ) AS
BEGIN
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 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
EXEC SearchAllTables 'Computer'][1]
[1]: https://koukia.ca/search-for-a-string-in-all-tables-and-all-fields-of-a-database-with-tsql-b6f8a1bfda37