Sp to sync two tables using linked servers sql server - sql-server

I'm working in a SP and I got two tables in different servers, one is the main and the other is a copy but whit less columns, all I want is to run the SP every 5 min over the main table in order to validate if new records has been created, if yes take those new records and insert them into the copy table, that resides in the other server.
Searching a solution I've found this script wich works ok in the same server, but when I try to run it with the linked server it fails....please somebody help me with this.
This is the error that a get....
OLE DB provider "SQLNCLI" for linked server "ESDBCGW001T" returned
message "The partner transaction manager has disabled its support for
remote/network transactions.". Msg 7391, Level 16, State 2, Procedure
sp_newrecords, Line 37 The operation could not be performed because
OLE DB provider "SQLNCLI" for linked server "LINKEDSERVER" was unable
to begin a distributed transaction.
All configurations are perfect, and when I run the insert without the variables runs fine,I mean, instead of #val1, #val2 and #val3 I use real values 1, 'A', 'B'.
USE [XXX]
GO
/****** Object: StoredProcedure [dbo].[sp_newrecords] Script Date: 03/02/2015 11:11:57 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
-- =============================================
-- Author: <>
-- Create date: <>
-- Description: <Description,,>
-- =============================================
ALTER PROCEDURE [dbo].[sp_newrecords]
-- Add the parameters for the stored procedure here
AS
BEGIN
DECLARE #val1 int
DECLARE #val2 nvarchar(50)
DECLARE #val3 nvarchar(50)
SET NOCOUNT ON;
-- Insert statements for procedure here
DECLARE mycur1 CURSOR for
select empid,fname,lname from employee
where empid = 508 --this is for test only
OPEN mycur1
FETCH NEXT FROM mycur1 INTO #val1, #val2 , #val3
WHILE ##Fetch_Status = 0
BEGIN
begin tran /* default read committed isolation level is fine */
if not exists (select * from openquery (linkedserver,'select * from DBNAME.dbo.Employee_backup'))
--insert employee_backup values (#val1, #val2 , #val3)
begin
INSERT into [linkedserver].[DBNAME].[dbo].[Employee_backup] values (#val1, #val2 , #val3)
end
/*if not exists (select * from employee_backup with (updlock, rowlock, holdlock)
where employee_backup.empid = #val1
and employee_backup.fname = #val2 )
--insert employee_backup values (#val1, #val2 , #val3)
INSERT [LINKEDSERVER].[DBNAME].[dbo].[Employee_backup] values (#val1, #val2 , #val3)*/
--else
-- /* update */
commit /* locks are released here */
FETCH NEXT FROM mycur1 INTO #val1, #val2 , #val3`enter code here`
END
CLOSE mycur1
DEALLOCATE mycur1
END

Your database admin would need to allow that permission on the target server. Personally, I would simply replicate the table from one server to the other and then the stored procedure would run against the replicated data.
If you absolutely need to go cross server, please refer to this SO question.

why not just use replication for something like this?
Might need to enable Distributed Transaction Coordinator (DTC) for your specific problem https://technet.microsoft.com/en-us/library/cc759136%28v=ws.10%29.aspx
In addition to ensuring DTC is enabled, you should be using begin distributed tran rather than begin tran
See:
https://msdn.microsoft.com/en-us/library/ms188386.aspx

Related

SQL Server stored procedures reading data before insert completed

I'm new to SQL Server and stored procedures and could do with a couple of pointers regarding transaction handling on a bug I've inherited.
I have two stored procedures, one inserts a record passed into it, then it calls another one where the first thing it does is read what was inserted.
But sometimes it completes successfully without processing the data. My suspicion is that the selects are happening before the insert has 'hit' the table and retrieve no records, and the stored procedure doesn't handle that.
I don't have time to re-engineer just yet, but the transaction handling looks suspect. Below is a rough outline of what the stored procedures do.
procedure sp1
(#id, #pbody)
as
begin
begin try
set nocount on;
begin
insert into tbl1 (id, tbody)
values (#id, #pbody)
exec sp2 #id
end
end try
begin catch
execute sperror
end catch
end
go
procedure sp2 (#id)
as
begin
begin try
set nocount on;
declare #vbody varchar(max)
select #vbody = tbody -- I don't believe this step always retrieves the row inserted by sp1
from tbl1 with (nolock)
where id = #id
create table #tmp1 (id, msg)
insert into #tmp1
select id, msg
from openjson........
while exists(select top 1 * from #tmp1) -- this looks similar to above, not sure the insert has finished before the read
begin
** do some stuff **
end
end try
begin catch
execute sperror
end catch
end
go
sp2 is using the WITH (NOLOCK) query hint, which can have unintended side-effects. Missing rows is just one of them.
Using NOLOCK? Here's How You'll Get the Wrong Query Results. - Brent Ozar UnlimitedĀ®
I'd strongly recommend removing that hint unless you really understand what it does and have a very good reason for using it.

SQL Server : SELECT from table updated during a Transaction

I have a stored procedure that contains the following logic:
Starts transaction scope using BEGIN TRANS A
Calls a second stored procedure where a record in Table1 is updated
Control returns to the original stored procedure where a SELECT is run against Table1
Commit transaction using COMMIT TRANS A
For some reason, that SELECT in step 3 is always returning the data values before the table was updated. I need the updated values from Step 2, that haven't been committed, to be returned by my SELECT.
How would I go about selecting the dirty/uncommitted data from Table1?
The scenarios described sounds a little off to me. You can begin a transaction and then execute a procedure. The data affected by that procedure is part of the transaction. This is painless to test and demonstrate.
create table TransactionDemo
(
SomeValue varchar(50)
)
insert TransactionDemo
select 'This is the original data.'
GO
create procedure TransactionDemoUpdate as
set nocount on;
update TransactionDemo
set SomeValue = 'This is updated data.'
GO
begin transaction
select * from TransactionDemo --data prior to calling procedure
exec TransactionDemoUpdate --will update the data
select * from TransactionDemo --see the values have changed
rollback transaction
select * from TransactionDemo --after the rollback they are the original values again.

Trigger fire on each inserted row to insert into remote Table

I have two different SQL 2008 servers, I don't have permission to create a linked server in any of them.
i created a trigger on server1.table1 to insert the same record to the remote server server2.table1 using OPENROWSET
i created a stored procedure to insert this record, and i have no issue when i execute the stored procedure. it insert the recored into the remote server.
the problem is when i call the stored procedure from trigger, i get an error message.
can anyone help me please to solve this issue
Stored Procedure:
USE [DB1]
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
alter PROCEDURE [dbo].[InsertIntoRemoteTable]
#Description nvarchar(50)
AS
insert into
OPENROWSET(
'SQLNCLI', 'Server=Server2;UID=MySRV2user;PWD=MySRV2Password',
'SELECT Description FROM [RemoteDB].[dbo].[Table_1]')
SELECT #Description
Trigger:
ALTER TRIGGER [dbo].[InsertTable1]
ON [DB1].[dbo].[Table_1]
for insert
AS
BEGIN
SET NOCOUNT ON;
DECLARE #Desc nvarchar(50)
Select #Desc = i.Descr from INSERTED i;
EXEC InsertIntoRemoteTable #Desc
END
When i try to insert a new description value in the table i got the following error message:
"No row was updated
the data in row 1 was not committed
Error source .Net SqlClient Data provider.
Error Message: the operation could not be performed because OLE DB
provider "SQLNCLI10" for linked server "(null)" returned message "The partner transaction manager has disabled its support for remote/network transaction.".
correct the errors entry or press ESC to cancel the change(s).
can anyone help please on this
thanks
I think you have over complicated this. There is really no need for a stored procedure here to do this. You can do this insert into another database directly in your trigger with a simple insert statement. This removes a ton of complexity and it is set based.
ALTER TRIGGER [dbo].[InsertTable1]
ON [DB1].[dbo].[Table_1]
for insert
AS
BEGIN
SET NOCOUNT ON;
INSERT INTO RemoteDB].[dbo].[Table_1](Description)
Select i.Descr
from INSERTED i;
END

Trouble creating SQL Server 2012 trigger

I'm quite new at SQL Server 2012, and I'm having a strange problem.
I've developed an AFTER UPDATE trigger on a table in my database. I created the trigger in our development environment which is an express edition of SQL Server 2012, no problem.
Now I have to create the same trigger in our production environment which is SQL Server 2012 Enterprise edition, and the creation script never stops executing, and the trigger is not created.
Any ideas on what I need to do to create the trigger?
The script :
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
alter TRIGGER [dbo].[til_aks_ved_betaling]
ON [dbo].[betalingsOplysningerbo]
AFTER UPDATE
AS
BEGIN
declare #snr uniqueidentifier
declare ##status varchar(1024)
SET NOCOUNT ON;
select
#snr = indmeldelse_snr
from
inserted
if UPDATE(betalingsDato)
begin
set ##status = 'Kalder med snr = ' + convert(varchar(38), #snr)
exec xp_logevent 60000, ##status , informational
exec overfoer_betalingsdato #snr
end
END
Try something like this....
ALTER TRIGGER [dbo].[til_aks_ved_betaling]
ON [dbo].[betalingsOplysningerbo]
AFTER UPDATE
AS
BEGIN
SET NOCOUNT ON;
declare #snr VARCHAR(1000);
declare #status varchar(1024);
DECLARE #Temp TABLE (indmeldelse_snr uniqueidentifier , [Status] varchar(1024))
INSERT INTO #Temp (indmeldelse_snr , [Status])
SELECT i.indmeldelse_snr , i.[Status]
FROM inserted i INNER JOIN deleted d
ON i.Snr = d.Snr AND i.betalingsDato <> d.betalingsDato
WHILE EXISTS(SELECT * FROM #Temp)
BEGIN
SELECT TOP 1 #snr = 'Kalder med snr = ' + convert(varchar(38),indmeldelse_snr )
,#status = [Status]
FROM #Temp
exec xp_logevent 60000, #status , informational
exec overfoer_betalingsdato #snr
DELETE FROM #Temp WHERE indmeldelse_snr = #snr
END
END
2 things here, common for new people, an UPDATE is a DELETE and an INSERT so make sure you have both before you assume it is an update. Second, these special tables will return all the rows affect by a single sql call. For example, Update Table SET This = 'That' will update every record in the table leaving INSERTED with MANY records.

When trigger failed to write in remote server, write to local server

First sorry for my English.
I have one server when receives an update in specific table, I want write to a remote server too, but if the remote server is unavailable, I want the trigger to write to the local server in another temp table.
Example code to write to remote server:
-- REMOTO is remote server
CREATE TRIGGER insertin
ON mangas
AFTER INSERT
AS
BEGIN
DECLARE #serie varchar(max), #capitulo int
SELECT #serie = serie ,#capitulo = capitulo
FROM inserted
INSERT INTO [REMOTO].[Gest].[dbo].[MARCA] (Codigo, Descripcion)
VALUES (#capitulo, #serie)
END
I need, for example, something like TRY...CATCH or similar. I don't know how can I do it.
Thanks for answers and sorry for my English again.
If using SQL Server 2005 or later, you can put a TRY...CATCH block round your INSERT statement. See MSDN: http://msdn.microsoft.com/en-US/library/ms175976(v=sql.90).aspx
BEGIN TRY
INSERT INTO [REMOTO].[Gest].[dbo].[MARCA]
(Codigo, Descripcion)
VALUES
( #capitulo, #serie )
END TRY
BEGIN CATCH
INSERT INTO [dbo].[MyTemporaryTable]
(Codigo, Descripcion)
VALUES
( #capitulo, #serie )
END CATCH
i do with this code and works well.
if anyone has better solution , please post, I'm learning t-sql now.
any advice is well come
begin
declare
#serie varchar(max),
#capitulo int,
#maxMarca int
select #serie = serie
from inserted
select #maxMarca =max(Codigo) from [REMOTO].[Gest].[dbo].[MARCA]
set #maxMarca = #maxMarca+1
commit -- save transaction insert which generates this trigger work.
begin TRANSACTION
BEGIN TRY
INSERT INTO [REMOTO].[Gest].[dbo].[MARCA] (Codigo, Descripcion) VALUES ( #maxMarca, #serie)
commit transaction --save transaction and finish, if remote server work
END TRY
BEGIN CATCH
IF ##trancount > 0
begin
rollback transaction --remote transaction is go back
INSERT INTO [mangas].[dbo].[mangasTemp] VALUES (#maxMarca, #serie)
commit transaction -- save transaction in local temporal table.
end
END CATCH
end
go

Resources