We do it similarly to you (but without transaction blocks, for the reason that you have encountered). Our way may fit with your current system of export to flat file.You could also look at Merge ReplicationLets say we have "Remote" clients and a "Local" central server.Remote client has a Stored Procedure which gathers new / changed data into Staging tables. We have date/time LastUpdated column on all our tables, so we can work out what has changed easily, but other applications we pull data from don't have that, so for those we have to do:SELECT *INTO #TEMPFROM OtherDatabase.dbo.SomeTable
Whichever method we use we then compare the data in #TEMP with our Staging tables with full WHERE clause to identify any row with one, or more, columns that have changed. (We only do this for columns that we are interested in - so the row may have changed on the Remote, but not in a column that we are interested in, so we don't want to transfer that).Delete from #TEMP any rows that are identical to Staging Table (don't want those!)DELETE TFROM #TEMP AS T JOIN StagingTable AS S ON S.PK_ID = T.PK_ID AND (S.Col1 = T.Col1 OR (S.Col1 IS NULL AND T.Col1 IS NULL) ... repeat for all columns of interest ...
(We force Binary Collation for VARCHAR columns so that we catch changes in just capitalisation)Then we pre-delete any existing rows from the Staging Table - to make room to import the newer rows:DELETE SFROM StagingTable AS S JOIN #TEMP T ON T.PK_ID = S.PK_ID
and then import them:INSERT INTO StagingTableSELECT [Action] = 'I', -- Insert [UpdateDate] = GetDate(), Col1, Col2, ...FROM #TEMP
then the Sproc calls an Sproc on the receiving end to transfer the data (this ensures that the operation is sequential)Note: The following is the code for the Sproc on the Local databaseThat does:DECLARE @strSQL varchar(8000), @LastestDate datetimeSELECT @LastestDate = MAX(UpdateDate) FROM StagingTable -- Get most recent date previously receivedSELECT @strSQL = 'SELECT *FROM RemoteDatabase.dbo.StagingTableWHERE UpdateDate > ''' + CONVERT(varchar(23), @LastestDate, 126) + ''''SELECT @strSQL = 'SELECT *INTO ##TEMPFROM OPENQUERY(LinkedServer, '''+ REPLACE(@strSQL, '''', '''''')+ ''')'EXEC (@strSQL)
that gets the newer staging data to the local server, that is then inserted into the local staging tables (no need to compare columns this time, if it was inserted at the far end we assume it should be inserted this end too)DELETE SFROM dbo.StagingTable AS S JOIN ##TEMP AS T ON T.PK_ID = S.PK_ID
Note that it may be necessary to force the collation on any PK columns that are Varchar if the database /server they came from has a different collationThen insert rows into the local staging tables:INSERT INTO dbo.StagingTableSELECT T.*FROM ##TEMP AS TDROP TABLE ##TEMP
then execute the SProc (on Local) that will process the data from the staging tables into real tables. That should store the LastestUpdate date in a Config table so it knows where it got to last time etc.The final operation to insert into the local staging table is atomic, so if the connection fails at any time some of the earlier tables being transferred may have completed, but there will be no insert into a single staging table which is only partially complete - the implicit atomic transaction will either complete, or rollback. Thus working on "More recent that LastUpdate" is safe.Also, the Remote Sproc "loads" its staging tables, then calls the Local Sproc to Pull the data, and then "loads" the local staging tables, and finally that then calls a Local Sproc to process the data means that the process is linear.It is important to prevent a second instance of that Sproc running concurrently (but a scheduled SQL Server task will not re-run if the earlier instance has not yet completed); you could also use Semaphores to prevent that.If you need to transfer Deletions too then the first step, at the remote end, should update the [Action] column for any records that no longer exist (in the remote application's database). This requires a full query of the PKs (and in generally we only do this once a day - however, most data we deal with seems to be retained, but marked as obsolete, rather than being physically deleted - but your application may be different of course!)I have some templates of the various Sprocs which I may be able to form into something suitable for publication if you need them.