SQL Server trigger operation with out cursor - sql

I have a scenario where in I have to generate SQL script after every DML operation. We have a trigger that runs after every Insert, Update, Delete.
Primarily it takes data from Inserted/Deleted tables and generates a SQL script for each row and performs an insert in to another table.
For example, If we insert
Take all inserted values
Open a cursor
For each inserted row, generate a SQL script that will be inserted in to another table for audit purpose
close cursor.
This trigger is taking almost 4-5 hours for 10,000 rows of 5 columns. Columns are int, date and varchar(100).
We are trying to replace the trigger. Need suggestions on same.
Set #syncScript = 'Insert Into table('
Declare insertCursor Cursor Local Forward_Only For
Select a, b, c From Inserted
Open insertCursor
Fetch Next From insertCursor Into #a, #b, #c
While (##Fetch_Status = 0)
Begin
Declare #valuesList varchar(max)
Set #columnList = ''
Set #paramsList = '['
Set #valuesList = ''
Select #columnList = #columnList + 'col6, ', #paramsList = #paramsList + '''' + COALESCE(dbo.ConvertFloatToVarchar(col6), 'NULL') + ''', ', #valuesList = #valuesList + '?, ' From Inserted I Where I.a= #a And I.b= #b And I.c= #c And 1 = 1
Select #columnList = #columnList + 'col5, ', #paramsList = #paramsList + '''' + COALESCE(Convert(varchar(max), col5), 'NULL') + ''', ', #valuesList = #valuesList + '?, ' From Inserted I Where I.a= #a And I.b= #b And I.c= #c And 1 = 1
Select #columnList = #columnList + 'col4, ', #paramsList = #paramsList + '''' + COALESCE(Convert(varchar(max), col4), 'NULL') + ''', ', #valuesList = #valuesList + '?, ' From Inserted I Where I.a= #a And I.b= #b And I.c= #c And 1 = 1
Select #columnList = #columnList + 'col3, ', #paramsList = #paramsList + '''' + COALESCE(Convert(varchar(max), col3), 'NULL') + ''', ', #valuesList = #valuesList + '?, ' From Inserted I Where I.a= #a And I.b= #b And I.c= #c And 1 = 1
Select #columnList = #columnList + 'col2, ', #paramsList = #paramsList + '''' + COALESCE(Convert(varchar(max), col2), 'NULL') + ''', ', #valuesList = #valuesList + '?, ' From Inserted I Where I.a= #a And I.b= #b And I.c= #c And 1 = 1
Select #columnList = #columnList + 'col1, ', #paramsList = #paramsList + '''' + COALESCE(Convert(varchar(max), col1), 'NULL') + ''', ', #valuesList = #valuesList + '?, ' From Inserted I Where I.TraitValueMemberId = #a And I.ValueSetId = #b And I.LanguageCulture = #c And 1 = 1
Set #columnList = SUBSTRING(#columnList, 1, Len(#columnList) - 1) + ') Values ('
Set #valuesList = SUBSTRING(#valuesList, 1, Len(#valuesList) - 1) + ')'
Set #paramsList = #paramsList + ']'
Set #bigScript = (COALESCE(#syncScript, '') + COALESCE(#columnList, '') + COALESCE(#valuesList, ''))
Insert Into Log (CreatedDate, [Message]) Select GetDate(), 'tablename INSERT syncScript = ' + #bigScript +'paramsList = ' + COALESCE(#paramsList, '')
Insert Into [dbo].[LogAudit] (GuidId, Query, Params, TableName, CreatedDate, Operation, UserId)
Values ('00000000-0000-0000-0000-000000000000', #bigScript, #paramsList, #table, GetDate(), #operation, #debugUser)
Fetch Next From insertCursor Into #a, #b, #c
End
Close insertCursor
Deallocate insertCursor
In case of update we join across inserted and deleted tables to generate update script like shown above.

I resolved the issue using SET Operation rather than Trigger
INSERT Into [dbo].[LogAudit] (GuidId, Query, Params, TableName, CreatedDate, Operation, UserId)
SELECT '00000000-0000-0000-0000-000000000000',
'INSERT INTO Table(col6, col5, col4, col3, col2, col1) VALUES (?, ?, ?, ?, ?, ?)',
'[' + '''' + COALESCE(dbo.ConvertFloatToVarchar(col6), 'NULL') + ''',' + '''' + COALESCE(Convert(varchar(max), col5), 'NULL') + ''', ' + '''' + COALESCE(Convert(varchar(max), col4), 'NULL') + ''', ' + '''' + COALESCE(Convert(varchar(max), col3), 'NULL') + ''', ' + '''' + COALESCE(Convert(varchar(max), col2), 'NULL') + ''', ' + '''' + COALESCE(Convert(varchar(max), col1), 'NULL') + ''', ' + ']', #table, GetDate(), #operation, #debugUser FROM Inserted
-- Insert into Log
Insert Into Log (CreatedDate, [Message]) Select GetDate(), 'MTDE_TraitValueMemberByLanguage_Sync INSERT
syncScript = INSERT Into [dbo].[LogAudit (GuidId, Query, Params, TableName, CreatedDate, Operation, UserId) VALUES VALUES (?, ?, ?, ?, ?, ?)' +
'paramsList = ' + '[' + '''' + COALESCE(dbo.ConvertFloatToVarchar(col6), 'NULL') + ''',' + '''' + COALESCE(Convert(varchar(max), col5), 'NULL') + ''', ' + '''' + COALESCE(Convert(varchar(max), col4), 'NULL') + ''', ' + '''' + COALESCE(Convert(varchar(max), col3), 'NULL') + ''', ' + '''' + COALESCE(Convert(varchar(max), col2), 'NULL') + ''', ' + '''' + COALESCE(Convert(varchar(max), col1), 'NULL') + ''', ' + ']' FROM Inserted

Related

SQL multiple where clauses

I have a procedure that has the options to take in Ids from three different columns I am concatenating all the where clauses together and then I EXEC the command.
Just wanted to see if there is a better way to do this?
IF ((ISNULL(#GuidelineIds, '')) <> '')
BEGIN
SET #whereClause = #whereClause + ' AND glinks.GuidelineId IN (SELECT val AS linkType FROM dbo.Split(''' + #GuidelineIds + ''','',''))'
END
IF ((ISNULL(#SubCategories, '')) <> '')
BEGIN
SET #whereClause = #whereClause + ' AND lt.LinkTypeID IN (SELECT val As subCategories FROM dbo.Split(''' + #SubCategories + ''', '',''))'
END
IF ((ISNULL(#LanguageIds, '')) <> '')
BEGIN
SET #whereClause = #whereClause + ' AND glinks.LanguageId IN (SELECT val As languages FROM dbo.Split(''' + #LanguageIds + ''', '',''))'
END
You can achieve it by this way
Select *
From ...
WHERE 1 = 1
AND ((ISNULL(#GuidelineIds, '')) = '' OR glinks.GuidelineId IN (SELECT val AS linkType FROM dbo.Split(''' + #GuidelineIds + ''','','')))
AND ((ISNULL(#SubCategories, '')) = '' OR lt.LinkTypeID IN (SELECT val As subCategories FROM dbo.Split(''' + #SubCategories + ''', '','')))
AND ((ISNULL(#LanguageIds, '')) = '' OR glinks.LanguageId IN (SELECT val As languages FROM dbo.Split(''' + #LanguageIds + ''', '','')))

Dynamic SQL - Insert a variables via INSERT INTO x SELECT statement

I would like to ask how can I insert a variables into a table using INSERT INTO x SELECT statement via dynamic SQL.
I have following table:
|-------------------|-----------------|--------------|-----------------|
| TableName | ColName | Value | SQL_Statement |
|-------------------|-----------------|--------------|-----------------|
I get a content for Value column by this query:
INSERT INTO #ReturnTable(Value) SELECT TreeHolder FROM prm.Schm_Root WHERE ParentTreeHolderId = 'DD040D31-4591-4658-A02E-A6ED00AB64F2';
But I need to fill whole table. Please consider that other values are variables, not SQL queries.
SELECT #TableSchema = TableSchema FROM #TableNames WHERE Id = #Counter;
SELECT #TableName = TableName FROM #TableNames WHERE Id = #Counter;
SELECT #ColName = ColName FROM #TableNames WHERE Id = #Counter;
SET #SQL_Statement = 'SELECT ' + #ColName + ' FROM ' + #TableSchema + '.' + #TableName + ' WHERE ' + #ColName + ' = ' + '''''' + CAST(#GuidArgument AS NVARCHAR(50)) + '''''' + ';';
Now I have this query that fills a table:
SET #SQL_String = N'INSERT INTO #ReturnTable SELECT
''' + #TableName + ''',
''' + #ColName + ''',
''' + #SQL_Statement + ''',
'' + Value + '',
(SELECT ' +
#ColName + '
FROM ' +
#TableSchema + '.' + #TableName + '
WHERE ' +
#ColName + ' = ''' + CAST(#GuidArgument AS NVARCHAR(50)) + '
'')';
EXECUTE sp_executesql #SQL_String
PRINT #SQL_String;
The thing I need is to rewrite this query from INSERT INTO ? VALUE to INSERT INTO ? SELECT format.
If I understand correctly, you want to insert SQL execute syntax string and it results in ReturnTable table.
I would let subquery SQL execute syntax save in a variable. because the will be more clear what you need to do.
Declare a new variable #SQL_excuteStatement variable to save your execute syntax.
the #SQL_Statement to carry the original SQL string.
set #SQL_Statement = 'SELECT ' + #ColName +
' FROM ' + #TableSchema + '.' + #TableName +
' WHERE ' + #ColName + ' = '+'''''' + CAST(#GuidArgument AS NVARCHAR(50)) + '''''';
and use select ... from table instead of subquery in select
There is a sample for you.
DECLARE #SQL_String NVARCHAR(MAX)
DECLARE #TableSchema NVARCHAR(MAX)
DECLARE #TableName NVARCHAR(MAX)
DECLARE #ColName NVARCHAR(MAX)
DECLARE #Counter int = 1
DECLARE #SQL_Statement NVARCHAR(MAX)
DECLARE #GuidArgument INT = 1
CREATE TABLE TableNames(
ID INT,
TableSchema NVARCHAR(100),
TableName NVARCHAR(100),
ColName NVARCHAR(100)
);
CREATE TABLE ReturnTable(
TableName NVARCHAR(100),
ColName NVARCHAR(100),
SQL_Statement NVARCHAR(max),
value nvarchar(max)
);
INSERT INTO TableNames VALUES (1,'dbo','T','val');
CREATE TABLE T(val INT);
INSERT INTO T VALUES (1)
SELECT #TableSchema = TableSchema FROM TableNames WHERE Id = #Counter;
SELECT #TableName = TableName FROM TableNames WHERE Id = #Counter;
SELECT #ColName = ColName FROM TableNames WHERE Id = #Counter;
set #SQL_Statement = 'SELECT ' + #ColName +
' FROM ' + #TableSchema + '.' + #TableName +
' WHERE ' + #ColName + ' = '+ '''''' + CAST(#GuidArgument AS NVARCHAR(50)) + '''''';
SET #SQL_String = N'INSERT INTO ReturnTable (TableName,ColName,SQL_Statement,value)
SELECT '''+ #TableName + ''','''+ #ColName + ''','''+ #SQL_Statement + '''' + ',' + QUOTENAME(#ColName) +
' FROM ' + QUOTENAME(#TableSchema) + '.' + QUOTENAME(#TableName) + '' +
' WHERE ' + #ColName + ' = ''' + CAST(#GuidArgument AS NVARCHAR(50)) + '''';
EXECUTE sp_executesql #SQL_String
sqlfiddle
Note
I would suggest you use clear column after insert into
INSERT INTO table2 (column1, column2, column3, ...)
SELECT column1, column2, column3, ...
FROM table1
WHERE condition;

Adding an apostrophe into a dynamic SQL

I would like to ask how can I add an apostrophe into a dynamic SQL. I need to return an SQL statement in one of the columns which has to have apostrophes in itself.
I have the following statement:
SET #SQL_String = N'INSERT INTO #ReturnTable
(
TableName,
ColName,
SQL_Statement,
Value
)
VALUES
(
''' + #TableName + ''',
''' + #ColName + ''',
''' +
'SELECT ' +
#ColName +
' FROM ' +
#TableSchema + '.' + #TableName +
' WHERE ' +
#ColName + ' = ' + CAST(#GuidArgument AS NVARCHAR(50)) + ';' +''',
(
SELECT
' + #ColName + '
FROM
' + #TableSchema + '.' + #TableName +
' WHERE '
+ #ColName + ' = ''' + CAST(#GuidArgument AS NVARCHAR(50)) +
'''))';
Executing with:
EXECUTE #RC = [dbo].[GetLocationOfGuidPre] 'F2CAB996-F00F-43B8-A67A-0000721A829D'
I need to put a whole first CAST into a pair of '.
I've tried:
Putting whole CAST statement into a separeted variable like: DECLARE #Test NVARCHAR(50);
SET #Test = CAST(#GuidArgument AS NVARCHAR(50));
SET #Test = 'CAST(#GuidArgument AS NVARCHAR(50))';
SET #Test = '''CAST(#GuidArgument AS NVARCHAR(50))''';
Addidng two more apostrophes:
' WHERE ' + #ColName + ' = ''' + CAST(#GuidArgument AS NVARCHAR(50)) + ''';'
Please use CHAR(39) instead of typing ' in your dynamic code directly.
Example:
declare #my_dynamic_sql nvarchar(max) = 'print char(39);';
exec(#my_dynamic_sql);

SQL : Select a table name containing specific string [duplicate]

This question already has answers here:
Find a value anywhere in a database
(18 answers)
Search all tables, all columns for a specific value SQL Server [duplicate]
(4 answers)
Closed 5 years ago.
Suppose I have string to search "Sample String" and I have 100 tables in my database.
I want to search if any of the table contains this string.
Eg. If tlbSample contains string "Sample String" then it should show it.
I tried :-
SELECT name
FROM sys.tables
WHERE name LIKE '%Sample String%'
But no luck.
Please help me.
You can use this. I have copied it from here : https://stackoverflow.com/a/13588431/400447
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

update special character columns dynamically for all columns of a table?

I want to replace special characters by normal characters in all columns dynamically for all columns of a table.But it works only for a column which is hardcoded
alter proc dbo.specialcharacterreplacer
#tblname varchar(1000),
#column_name varchar(1000)
as
begin
declare #Sql VARCHAR(MAX)
set #Sql = '
UPDATE ' + #tblname + ' SET ' + #column_name+ ' = REPLACE('+#column_name + ', ' + '''ó'''+ ', '+'''o'''+')
UPDATE ' + #tblname + ' SET ' + #column_name+ ' = REPLACE('+#column_name + ', ' + '''ò'''+ ', '+'''o'''+')
UPDATE ' + #tblname + ' SET ' + #column_name+ ' = REPLACE('+#column_name + ', ' + '''ö'''+ ', '+'''o'''+')
UPDATE ' + #tblname + ' SET ' + #column_name+ ' = REPLACE('+#column_name + ', ' + '''ð'''+ ', '+'''o'''+')
exec (#sql)
end
go
EXEC dbo.specialcharacterreplacer #tblname = 'dirtyyyysource', #column_name ='select *from INFORMATION_SCHEMA.COLUMNS where TABLE_NAME = '#tblname''
how to make columns dynamic?
This was the central code to get your update statement for all columns of a given table dynamically. Be aware of TABLE_SCHEMA and the column's type. You might use some additions in the WHERE part... (in my example you'd try to replace the INT column as well...)
And you might have a look here: https://stackoverflow.com/a/32048968/5089204
There you'll find one of my former answers to a similar question and shows an approach how to create a function which will replace several special characters in one go.
CREATE TABLE dbo.TestTable(ID INT,Test1 VARCHAR(100), Test2 VARCHAR(100));
GO
declare #tblname varchar(1000)='TestTable';
declare #tblschema varchar(1000)='dbo';
DECLARE #SqlCmd VARCHAR(MAX)= 'UPDATE ' + #tblname + ' SET ' +
(
STUFF(
(
SELECT ',' + COLUMN_NAME + ' = REPLACE(' + COLUMN_NAME + ', ' + '''ó'', ''o'''+')'+ CHAR(10) --might need to use CHAR(13)+CHAR(10)
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_SCHEMA=#tblschema AND TABLE_NAME = #tblname
FOR XML PATH('')
),1,1,'') + ';'
);
SELECT #SqlCmd;
GO
DROP TABLE dbo.TestTable;
GO
The result:
UPDATE TestTable SET ID = REPLACE(ID, 'ó', 'o')
,Test1 = REPLACE(Test1, 'ó', 'o')
,Test2 = REPLACE(Test2, 'ó', 'o')
;