We have two sql servers(e.g server1 & server2). We have created table on server1 and used as linkserver on server2.Also we have trying to create trigger on that table via server2 but its throws an error.So please let me know how to create insert trigger using linkserver?
exec ('
use mydb;
create table dbo.testtable(id int);
exec(''
create trigger testtrigger on dbo.testtable
for insert
as
begin
select object_name(##procid), *
from inserted;
end
'');
') at linked_server_name;
go
exec ('insert into mydb.dbo.testtable(id) values (1), (2), (3)') at linked_server_name;
go
exec ('drop table mydb.dbo.testtable') at linked_server_name;
Related
I'm trying to implement a trigger to audit the updates made to a table. In the trigger I create a temp table to store the results of a call to DBCC InputBuffer:
CREATE TABLE #inputbuffer (
EventTypevarchar(255),
Parametersint,
EventInfovarchar(255)
)
INSERT INTO #inputbuffer
exec('dbcc inputbuffer(' + ##spid + ') WITH NO_INFOMSGS ')
But there are a lot of SP's that make some Insert Exec statements and update the table with the trigger, so error 'An INSERT EXEC statement cannot be nested.' is shown.
Is there a way to catch the results of inputbuffer other than an Insert Exec? sys.dm_exec_sql_text cannot be used because it requires VIEW SERVER STATE permission on the server for user who triggers trigger.
I need to execute a query before every insert into the table. I try to use instead of
--insert into tbl_Exlog(ActionName) values('Insert')
--select * from tbl_Exlog
ALTER Trigger [dbo].[trgExLogTest] on [dbo].[tbl_ExLog]
Instead of Insert
as
begin
insert into tbl_ExLog (ActionName) values('trigger')
end
but it restricts the actual insert which I don't want.
Output :
ActionName
trigger
Insert is missing
The INSERT is missing, yes, in your TRIGGER. You never told SQL Server to INSERT the data, so it doesn't INSERT it. An INSTEAD OF INSERT "does exactly what it says on the tin"; 'do this instead of the INSERT'. You tell SQL Server to INSERT a row into tbl_ExLog instead but don't tell it to INSERT into the table you were actually inserting again.
Define the INSERT in your trigger:
ALTER TRIGGER [dbo].[trgExLogTest] ON [dbo].[tbl_ExLog]
INSTEAD OF INSERT AS
BEGIN
INSERT INTO dbo.tbl_ExLog (ActionName) VALUES ('trigger');
INSERT INTO dbo.trgExLogTest ({Column List})
SELECT {Column List}
FROM inserted;
END;
I have 2 procedures proc_Data, proc_FetchData.
I'm calling proc_Data from within proc_FetchData. proc_Data returns 2 tables. I want to insert only the first table into a temp table in my second procedure and use it further.
The problem is I cannot change proc_Data in any way as this is a very old procedure used in various parts of our application.
Sample code for reference
create procedure proc_Data
As
Begin
select 'Apples'
select 'Oranges','Grapes'
end
create procedure proc_FetchData
As
Begin
create table #temp(Data varchar(30))
insert into #temp
exec Test_proc
select * from #temp
end
I'm using SQL Server 2014 - is there any way to achieve this? Thanks in advance.
You cant do it that way, you can split your first SP into 2 and call it in your second SP, like,
create procedure proc_Data1
As
Begin
select 'Apples'
end
GO
create procedure proc_Data2
As
Begin
select 'Oranges','Grapes'
end
GO
ALTER procedure proc_FetchData
As
Begin
create table #temp(
Data varchar(30)
)
insert into #temp
exec proc_Data1
select * from #temp
end
To insert only the first table you can use OPENROWSET.
create procedure proc_FetchData
As
Begin
declare #userData TABLE(Data NVARCHAR(30))
INSERT INTO #userData
SELECT * FROMOPENROWSET('SQLNCLI','Server=[server];Trusted_Connection=yes;','EXEC [database name].dbo.proc_Data')
select * from #userData
end
If you need to access all resultsets you will need to use SQLCLR proc: https://social.msdn.microsoft.com/Forums/sqlserver/en-US/da5328a7-5dab-44b3-b2b1-4a8d6d7798b2/insert-into-table-one-or-multiple-result-sets-from-stored-procedure?forum=transactsql
I suggest you add a new input parameter with a default value to your procedure and return different datasets depended on its value.
ALTER procedure proc_Data
#Mode INT = 0
As
Begin
IF #Mode = 0 BEGIN
select 'Apples'
select 'Oranges','Grapes'
END
ELSE BEGIN
select 'Apples'
END
end
go
ALTER procedure proc_FetchData
As
Begin
create table #temp(Data varchar(30))
insert into #temp
exec proc_Data #Mode = 1
select * from #temp
end
After doing so, you will be able to use your proc_Data in any old queries without changes, whereas its output will be different with different #Mode values if you need.
I have 2 store procedure :
The first one to create #TempTable
CREATE PROCEDURE CreateTempTable
AS
BEGIN
IF OBJECT_ID('tempdb..#TempTable') IS NOT NULL
BEGIN
DROP TABLE #TempTable;
END
CREATE TABLE #TempTable(
Value real NOT NULL
END
The second one to insert data in my #TempTable
CREATE PROCEDURE InsertData
#Value real
AS
BEGIN
INSERT #TempTable (Value) VALUES #Value
END
When I call these procedure I have an error :
exec CreateTempTable
exec InsertData" 1
go
Name '#TempTable' not valid in InsertData
Can you help me ?
A temp table created inside a sproc is automatically dropped after the sproc ends.
You have a few choices:
Create the temp table outside of the sproc as a standalone query. Then it will be dropped after the connection closes
Create a sproc that first creates the temp table and then calls the other sprocs
Use a global temp table (careful - concurrency issues can crop up with this)
I guess the problem here is that you are creating a local temporary table, that cannot be accessed outside CreateTempTable. You should create a global temporary table, by using ## instead of #.
Edit Yep, that's it. Here is your fixed script:
CREATE PROCEDURE CreateTempTable
AS
BEGIN
IF OBJECT_ID('tempdb..##TempTable') IS NOT NULL
BEGIN
DROP TABLE ##TempTable;
END
CREATE TABLE ##TempTable(
Value real NOT NULL
)
END
GO
CREATE PROCEDURE InsertData
#Value real
AS
BEGIN
INSERT ##TempTable (Value) VALUES (#Value)
END
GO
exec CreateTempTable
exec InsertData 1
go
I have 2 stored procedures usp_SP1 and usp_SP2. Both of them make use of insert into #tt exec sp_somesp. I wanted to create a 3rd stored procedure which will decide which stored proc to call. Something like:
create proc usp_Decision
(
#value int
)
as
begin
if (#value = 1)
exec usp_SP1 -- this proc already has insert into #tt exec usp_somestoredproc
else
exec usp_SP2 -- this proc too has insert into #tt exec usp_somestoredproc
end
Later, I realized I needed some structure defined for the return value from usp_Decision so that I can populate the SSRS dataset field. So here is what I tried:
Within usp_Decision created a temp table and tried to do "insert into #tt exec usp_SP1". This didn't work out. error "insert exec cannot be nested"
Within usp_Decision tried passing table variable to each of the stored proc and update the table within the stored procs and do "select * from ". That didn't work out as well. Table variable passed as parameter cannot be modified within the stored proc.
Please suggest what can be done.
Can you modify usp_SP1 and usp_SP2?
If so, in usp_Decision, create a local temporary table with the proper schema to insert the results:
create table #results (....)
Then, in the called procedure, test for the existence of this temporary table. If it exists, insert into the temporary table. If not, return the result set as usual. This helps preserve existing behavior, if the nested procedures are called from elsewhere.
if object_id('tempdb..#results') is not null begin
insert #results (....)
select .....
end
else begin
select ....
end
When control returns to the calling procedure, #results will have been populated by the nested proc, whichever one was called.
If the result sets don't share the same schema, you may need to create two temporary tables in usp_Decision.
Have you had a look at table-valued user-defined functions (either inline or multi-statement)? Similar to HLGEM's suggestion, this will return a set which you may not have to insert any where.
Not a fan of global temp tables in any event (other processes can read these table and may interfere with the data in them).
Why not have each proc use a local temp table and select * from that table as the last step.
Then you can insert into a local temp table in the calling proc.
esimple example
create proc usp_mytest1
as
select top 1 id into #test1
from MYDATABASE..MYTABLE (nolock)
select * from #test1
go
--drop table #test
create proc usp_mytest2
as
select top 10 MYTABLE_id into #test2
from MYDATABASE..MYTABLE (nolock)
select * from #test2
go
create proc usp_mytest3 (#myvalue int)
as
create table #test3 (MYTABLE_id int)
if #myvalue = 1
Begin
insert #test3
exec ap2work..usp_mytest1
end
else
begin
insert #test3
exec ap2work..usp_mytest2
end
select * from #test3
go
exec ap2work..usp_mytest3 1
exec ap2work..usp_mytest3 0
See this blog article for one wortkaround (uses OPENROWSET to essentially create a loopback connection on which one of the INSERT EXEC calls happens)