Dynamic, cross database trigger creation - sql

I am trying to dynamically create a number of triggers across two databases but I am having problems with the Create Trigger statement when switching databases
SET #SQL = 'SELECT Name FROM ' + #DB + '.sys.triggers WHERE Name = ' + ''''
+ #Table + '_DELTATrigger' + ''''
EXEC(#SQL)
IF ##RowCount > 0
BEGIN
SET #SQL = 'USE ' + #DB + '; DROP TRIGGER [dbo].[' + #Table + '_DELTATrigger]'
EXEC(#SQL)
END
SET #SQL = 'CREATE TRIGGER [dbo].[' + #Table + '_DELTATrigger]
ON [dbo].[' + #Table + ']
AFTER INSERT, UPDATE
AS
BEGIN
SET NOCOUNT ON
UPDATE [' + #Table + ']
SET [Delta] = 1
FROM inserted
WHERE inserted.[ID] = [' + #Table + '].[ID]
END;'
EXEC (#SQL)
If I run this statement I get the following issue
Error 8197, Level 16, State 4, Procedure tblBuild_DataPlate_DELTATrigger, Line 1
Message: The object 'dbo.tblBuild_DataPlate' does not exist or is
invalid for this operation.
Changing the dynamic create trigger to include the USE statement does not work as the Create Trigger has to be the first statement
SET #SQL = 'USE ' + #DB + '; CREATE TRIGGER [dbo].[' + #Table + '_DELTATrigger]
ON [dbo].[' + #Table + ']
AFTER INSERT, UPDATE
AS
BEGIN
SET NOCOUNT ON
UPDATE [' + #Table + ']
SET [Delta] = 1
FROM inserted
WHERE inserted.[ID] = [' + #Table + '].[ID]
END;'
EXEC (#SQL)
Error 111, Level 15, State 1, Procedure -,
Line 1, Message: 'CREATE TRIGGER' must be the first
statement in a query batch.
You can not fully qualify the object with the database in this case as you get the following error
Error 166, Level 15, State 1, Procedure -, Line 1,
Message: 'CREATE/ALTER TRIGGER' does not allow
specifying the database name as a prefix to the object name.
Is there a dynamic way around this?

This code below will run the sp_executesql on the selected database (#DB), so with this, you can create the trigger on the rigth place:
SET #SQL = 'EXEC ' + #DB + '..sp_executesql N''
CREATE TRIGGER [dbo].[' + #Table + '_DELTATrigger]
ON [dbo].[' + #Table + ']
AFTER INSERT, UPDATE
AS
BEGIN
SET NOCOUNT ON
END;'''
EXEC (#SQL)

Related

stored procedure to remove quotes

I am trying to write a stored procedure that will removed leading and trailing quotes from an arbitrary table and column. I keep getting an error saying that the table name isn't declared.
Here is the SP
create table [dbo].[test] (id nvarchar(20))
insert into dbo.test values ('"07617966004766"')
go
CREATE PROCEDURE sp_stripDoubleQuotes
#tableName sysname,
#columnName sysname
AS
BEGIN
SET NOCOUNT ON;
UPDATE #tableName
SET #columnName = SUBSTRING(#columnName, 2, LEN(#columnName))
WHERE LEFT(#columnName, 1) = '"'
UPDATE #tableName
SET #columnName = SUBSTRING(#columnName, 1, LEN(#columnName)-1)
WHERE RIGHT(#columnName, 1) = '"'
END
GO
exec [dbo].[sp_stripDoubleQuotes] N'[dbo].[test]', N'[id]'
select * from test
Here is a link to a fiddle:
link to fiddle
CREATE PROCEDURE sp_stripDoubleQuotes
#tableName sysname,
#columnName sysname,
#SQL varchar(MAX)
AS
BEGIN
SET NOCOUNT ON;
SET #SQL =
'UPDATE ' + '[' + #tableName +']' +
'SET' + '[' + #columnName +']' +'= SUBSTRING(' +'[' + #columnName +']' +', 2, LEN(' +'[' + #columnName +']' +'))
WHERE LEFT(' + '[' + #columnName +']' +', 1) = '+'''"'''
--PRINT(#SQL)
EXEC (#SQL)
SET #SQL =
'UPDATE ' + '[' + #tableName +']' +
'SET' + '[' + #columnName +']' +'= SUBSTRING(' + '[' + #columnName +']' +', 1, LEN(' + '[' + #columnName + ']' +')-1)
WHERE RIGHT(' + '[' + #columnName +']' +', 1) = '+'''"'''
--PRINT(#SQL)
EXEC (#SQL)
END
GO
exec [dbo].[sp_stripDoubleQuotes] N'test', N'id' -- exec [dbo].[sp_stripDoubleQuotes] N'[dbo].[test]', N'[id]'
Updated 2nd: I added [] to wrap table and column incase your table and column name have whitespace in them. Thanks #Sean Lange and #Richard
Updated 3rd: As #[benjamin moskovits] (xD) mentioned, if you hard coded brackets, the correct execute command is exec [dbo].[sp_stripDoubleQuotes] N'test', N'id'. Try to add or remove brackets and print to see whether the syntax is correct before executing it.
CREATE PROCEDURE sp_stripDoubleQuotes
#tableName sysname,
#columnName sysname
AS
BEGIN
SET NOCOUNT ON;
declare #QuerytoExecute varchar(1000)
set #QuerytoExecute="UPDATE "+#tableName+"
SET "+#columnName+" = SUBSTRING("+#columnName+", 2, LEN("+#columnName+"))
WHERE LEFT("+#columnName+", 1) = '""'";
exec (#QuerytoExecute);
set #QuerytoExecute="
UPDATE "+#tableName+"
SET "+#columnName+" = SUBSTRING("+#columnName+", 1, LEN("+#columnName+")-1)
WHERE RIGHT("+#columnName+", 1) = '""'";
exec (#QuerytoExecute);
END
GO

Using a variable as table name fails

Why does this fail with the following error message:
Msg 102, Level 15, State 1, Line 1
Incorrect syntax near 'reporting_rawdata_v2'.
the name of the table is "dbo.reporting_rawdata_v2" but either with/without "dbo" it still fails...
Use reporting2
Go
Declare #Backupdate varchar(25), #sql NVARCHAR(max)
Set #Backupdate = REPLACE(REPLACE(CAST(CONVERT(VARCHAR(20), SYSDATETIME(), 100) as varchar),' ','_'),':', '')
Select #Backupdate
SET #sql = 'Select * Into reporting_rawdata_BACKUP_' + #Backupdate + 'From reporting_rawdata_v2';
EXEC (#sql);
No space between dynamically named table and From
SET #sql = 'Select * Into reporting_rawdata_BACKUP_' + #Backupdate + ' From reporting_rawdata_v2';
EXEC (#sql);

Database distribution dose not exist in sp_replmonitorsubscriptionpendingcmds

I'm creating a dynamic SQL log that will tell me the unpending transaction.
I'm trying to enter sp_replmonitorsubscriptionpendingcmds into a table for that reason in need to execute it as sp_executesql.
For some reason when I finish running the script it says
Msg 911, Level 16, State 4, Line 1
Database 'distribution' does not exist. Make sure that the name is entered correctly.
and im running it on distribution database.
Thank you for your help
set #counter = 1
while #counter <#NOR
BEGIN
select #v_publisher=servername,
#v_publisher_db=DbName,
#v_publication = DbName+'_1way',
#v_subscriber = ##servername,
#v_subscriber_db =DbName
from Serverses
where id = #counter
SET #sql = N'SELECT * INTO #pendingcmds
FROM OPENROWSET(''SQLOLEDB'',''SERVER=(LOCAL);TRUSTED_CONNECTION=YES''
,''SET FMTONLY OFF EXEC distribution.dbo.sp_replmonitorsubscriptionpendingcmds #publisher=['
+ #v_publisher + '],
#publisher_db='+ #v_publisher_db + ',
#publication='+ #v_publication + ',
#subscriber=['+ #v_subscriber + '],
#subscriber_db='+ #v_subscriber_db + ',
#subscription_type=' + CONVERT(CHAR(1),#pubtype) + ''')'
select #sql
EXEC sp_executesql #sql
set #counter=#counter+1
END

How do I create an index inside a stored procedure?

How do I create an index inside a stored procedure? It complains
Msg 102, Level 15, State 1, Procedure createIndexModifiedOn, Line 12
Incorrect syntax near 'PRIMARY'.
But ON [PRIMARY] is what SQL Server itself uses if you create a new index and select Script As New Query.
If I remove ON [PRIMARY] then it gives this error
Msg 102, Level 15, State 1, Procedure createIndexModifiedOn, Line 12
Incorrect syntax near ')'.
Here is the procedure:
create proc [dbo].createIndexModifiedOn
#table char(256)
as begin
declare #idx char(256)
set #idx = 'idx_' + SUBSTRING(#table, 7, len(#table)-1) + '_modified_on';
IF EXISTS (SELECT * FROM sys.indexes WHERE object_id = OBJECT_ID(#table) AND name = #idx)
DROP INDEX [#idx] ON [#table]
CREATE NONCLUSTERED INDEX [#idx] ON [#table]
(
[modified_on] ASC
) ON [PRIMARY]
go
This ended up being the full query:
create proc [dbo].createIndexModifiedOn
#table varchar(256)
as
declare #idx varchar(256);
declare #sql nvarchar(999);
set #idx = 'idx_' + SUBSTRING(#table, 8, len(#table)-8) + '_modified_on';
set #sql = '
IF EXISTS (SELECT * FROM sys.indexes WHERE object_id = OBJECT_ID(''' + #table + ''') AND name = ''' + #idx + ''')
DROP INDEX [' + #idx + '] ON ' + #table + '
CREATE NONCLUSTERED INDEX [' + #idx + '] ON ' + #table + '
(
[modified_on] ASC
) ON [PRIMARY]
';
print #table + ', ' + #idx;
BEGIN TRY
EXEC sp_executesql #sql;
END TRY
BEGIN CATCH
PRINT 'errno: ' + ltrim(str(error_number()))
PRINT 'errmsg: ' + error_message()
END CATCH
GO
EXEC sp_MSforeachtable 'exec createIndexModifiedOn "?"'
You can't use variables in the CREATE INDEX statement as you have. To do this, you will need to generate a SQL string and execute it with sp_executesql.
Freehand example:
DECLARE #sql NVARCHAR(1024);
SET #sql = 'CREATE NONCLUSTERED INDEX [' + #idx + '] ON [' + #table + ']
(
[modified_on] ASC
) ON [PRIMARY];';
EXEC sp_executesql #sql;

sql create database from variable

I have #db_out = 'aux.dbo.some_table_name' , and I don't know how to drop , create based on that variable like :
IF OBJECT_ID(#db_out) IS NOT NULL DROP TABLE "#db_out" - not working
CREATE TABLE "#db_out" .... etc
it creates master.dbo.#dbo_out
How can I use that variable to create that table or verify it and drop it ?
You will have to build the statement in varchar variable and execute it:
declare #strSql as varchar(max)
IF OBJECT_ID(#db_out) IS NOT NULL
BEGIN
EXEC ('DROP TABLE [' + #db_out + ']')
END
set #strSql = 'CREATE TABLE [' + #db_out + '] (' -- Etc
EXEC (#strSql)
You need to write dynamic SQL.
SET #sql = 'IF OBJECT_ID(#db_out) IS NOT NULL DROP TABLE ' + #db_out + '; '
SET #sql = #sql + 'CREATE TABLE ' + #db_out + ' (...)'
EXEC(#sql)