I am trying to copy data from 2 tables linked by a foreign key on one server and then inserted them into the master database on another server.
The first table will generate a new IDENTITY column and then I want to store this in a variable and insert it into the 2nd table.
I have tried both using internal inserted tables and also SCOPE_IDENTITY() but receive errors that this is not allowed on a REMOTE server
DECLARE
#VisitSourceId int,
#SiteDomainId int,
#trpUTMid bigint,
#FlightPlus bit,
#StartDate datetime,
#CountryId int,
#ProvinceId int,
#Locationid int,
#PlaceId int,
#EstabId int,
#CheckInDate smalldatetime,
#CheckOutDate smalldatetime,
#Rooms int,
#Room1Adults int,
#Room1Children int,
#Room2Adults int,
#Room2Children int,
#Room3Adults int,
#Room3Children int,
#OutcomeDate datetime,
#OutcomeId smallint,
#HotelsFound smallint,
#Notes nvarchar,
#id bigint
DECLARE c CURSOR STATIC FOR
SELECT t.VisitSourceId, t.SiteDomainId, t.trpUTMid, t.FlightPlus, t.StartDate, t.CountryId, t.ProvinceId, t.Locationid,
t.PlaceId, t.EstabId, t.CheckInDate, t.CheckOutDate, t.Rooms, t.Room1Adults, t.Room1Children, t.Room2Adults, t.Room2Children, t.Room3Adults,
t.Room3Children, tc.OutcomeDate, tc.OutcomeId, tc.HotelsFound, tc.Notes
FROM [MLT_VisitTracking].[dbo].TrackingAcomSearches_tbl t
INNER JOIN TrackingAcomSearchesOutcome_tbl tc
ON t.trpUTMid = tc.trpUTMid
open c
FETCH FIRST FROM c INTO #VisitSourceId, #SiteDomainId, #trpUTMid, #FlightPlus, #StartDate, #CountryId, #ProvinceId, #Locationid,
#PlaceId, #EstabId, #CheckInDate, #CheckOutDate, #Rooms, #Room1Adults, #Room1Children, #Room2Adults, #Room2Children, #Room3Adults,
#Room3Children, #OutcomeDate, #OutcomeId, #HotelsFound, #Notes
while ##fetch_status=0
begin
DECLARE #TmpTable TABLE (ID BIGINT)
INSERT INTO [YAZOO].[MLT_VisitTracking].[dbo].TrackingAcomSearches_tbl
(VisitSourceId, SiteDomainId, trpUTMid, FlightPlus, StartDate, CountryId, ProvinceId, Locationid,
PlaceId, EstabId, CheckInDate, CheckOutDate, Rooms, Room1Adults, Room1Children, Room2Adults, Room2Children, Room3Adults,
Room3Children)
OUTPUT inserted.searchid into #TmpTable
SELECT #VisitSourceId, #SiteDomainId, #trpUTMid, #FlightPlus, #StartDate, #CountryId, #ProvinceId, #Locationid,
#PlaceId, #EstabId, #CheckInDate, #CheckOutDate, #Rooms, #Room1Adults, #Room1Children, #Room2Adults, #Room2Children, #Room3Adults,
#Room3Children
select top 1 #id = searchid from #tmptable
INSERT INTO [YAZOO].[MLT_VisitTracking].[dbo].TrackingAcomSearchesOutcome_tbl
(SearchId,
trpUTMid,
OutcomeDate,
OutcomeId,
HotelsFound,
Notes)
SELECT #id,
#trpUTMid,
#OutcomeDate,
#OutcomeId,
#HotelsFound,
#Notes
DELETE FROM [MLT_VisitTracking].[dbo].TrackingAcomSearches_tbl WHERE trpUTMid=#trpUTMid
DELETE FROM [MLT_VisitTracking].[dbo].TrackingAcomSearchesOutcome_tbl WHERE trpUTMid=#trpUTMid
FETCH NEXT FROM c INTO #VisitSourceId, #SiteDomainId, #trpUTMid, #FlightPlus, #StartDate, #CountryId,
#ProvinceId, #Locationid, #PlaceId, #EstabId, #CheckInDate, #CheckOutDate, #Rooms, #Room1Adults, #Room1Children,
#Room2Adults, #Room2Children, #Room3Adults, #Room3Children, #OutcomeDate, #OutcomeId, #HotelsFound, #Notes
end
close c
deallocate c
##IDENTITY and SCOPE_IDENTITY() are local
are you using a linked server?
check this:
get ##Identity from another server(linked server)
To resolve the issue I finally created the script on the target server as a stored procedure, then I could use scope identity. The performance also improved massively, I then configured a new linked server with RPC out enabled and called the procedure remotely. It is not an elegant solution, but its only temporary
Related
Currently have this query:
ALTER PROCEDURE [dbo].[spCreateTaskInstances]
#TaskId INT,
#CreatedByUserId INT,
#DueDates dbo.DateList READONLY
AS
BEGIN
SET NOCOUNT ON
INSERT INTO dbo.taskinstance (TaskId, CreatedById, DueDate, RowGuid, CreatedDate)
VALUES (#TaskId, #CreatedByUserId,
(SELECT CAST(d.item as date) FROM #DueDates d),
NEWID(), GETUTCDATE())
END
Obviously, this fails because when I pass more than one DateTime.
Am I forced to use a for loop here?
Just use that table-valued parameter like table - proper set-based approach, no messy while or for loop needed:
ALTER PROCEDURE [dbo].[spCreateTaskInstances]
#TaskId INT,
#CreatedByUserId INT,
#DueDates dbo.DateList READONLY
AS
BEGIN
SET NOCOUNT ON
INSERT INTO dbo.taskinstance (TaskId, CreatedById, DueDate, RowGuid, CreatedDate)
SELECT
#TaskId, #CreatedByUserId, CAST(d.item AS DATE), NEWID(), GETUTCDATE()
FROM
#DueDates d
END
I have an order table that has both past membership data and current data. I want to view this data in single row. I have a temp table for past data, but not exactly sure how to write this query to get current data in the same row. I know it has something to do with the MAX(order no). Here is the query to get the past membership data in a temp table
set transaction isolation level read uncommitted
declare
#ship_master_customer_id varchar (10), #cycle_begin_date datetime, #cycle_end_date datetime, #OrderNo varchar(10), #Description Char(100)
create table #t1(ShipMasterCustomerID varchar(10), OrderNo varchar (10), cycle_begin_date datetime, cycle_end_date datetime, Description Char(100))
Insert into #t1
Select SHIP_MASTER_CUSTOMER_ID, ORDER_NO, CYCLE_BEGIN_DATE,CYCLE_END_DATE, DESCRIPTION FROM [ORDER_DETAIL]
where SHIP_MASTER_CUSTOMER_ID = '11115555' and
CYCLE_END_DATE = '2/29/2016'
Select * from #t1
Drop table #t1
Here is my script.
declare
#ship_master_customer_id varchar (10), #cycle_begin_date datetime, #cycle_end_date datetime, #OrderNo varchar(10), #Description Char(100)
create table #t2(ShipMasterCustomerID varchar(10), OrderNo varchar (10), cycle_begin_date datetime, cycle_end_date datetime, Description Char(100))
Insert into #t2 (shipmastercustomerid, orderno, cycle_begin_date, cycle_end_date, DESCRIPTION)
VALUES (1111555,9004731815, 2015/01/01, 2015/31/12,'Annual Mem'),
(1111555, 9005148308, 2016/01/01, 2016/31/12,'Annual Mem'),
(1111222, 9005027152, 2015/01/03, 2016/29/02,'Annual Mem'),
(1111222, 9005440369, 2016/01/03, 2017/31/03,'Annual Mem'),
(2223333, 9005027152, 2014/01/01, 2016/31/12,'Annual Mem'),
(2223333, 9005442116, 2016/01/01, 2017/31/12,'Annual Mem')
Select * from #t2
Drop table #t2
Sample Data
You don't need a temp table. You can query the same table twice, giving it an alias and then use the alias to prefix your column names. Since you didn't give us a complete schema or a fiddle I'm simulating your database with a temp table but the essence is here. There are considerations that you didn't mention, though. Are you guaranteed that every customer will have both a historical AND a current record? If not, they will not appear in the query below because of the INNER JOIN. You could change it to an OUTER join but when customers don't have a new record you will see NULL values in those columns. My point is that here be dragons... this is by no means a complete or bulletproof solution, only a nudge in the right direction.
DECLARE #ORDER_DETAIL AS TABLE(
ShipMasterCustomerId varchar(20),
OrderNo varchar(20),
cycle_begin_date date,
cycle_end_date date,
Description varchar(100)
)
INSERT #ORDER_DETAIL SELECT '11115555', '9005337015', '02/26/15', '2/29/16', 'Membership 26-Feb-2015 to 29-Feb-2016'
INSERT #ORDER_DETAIL SELECT '11115555', '9005743023', '02/28/17', '2/28/17', 'Membership 01-Mar-2016 to 28-Feb-2017'
SELECT
hist.ShipMasterCustomerId,
hist.OrderNo,
hist.cycle_begin_date,
hist.CYCLE_END_DATE,
hist.[Description],
curr.ShipMasterCustomerId,
curr.OrderNo,
curr.cycle_begin_date,
curr.CYCLE_END_DATE,
curr.[Description]
FROM
#ORDER_DETAIL AS hist
INNER JOIN #ORDER_DETAIL AS curr ON (
(curr.ShipMasterCustomerId = hist.ShipMasterCustomerId) AND (curr.cycle_end_date =
(SELECT MAX(cycle_end_date) FROM #ORDER_DETAIL WHERE ShipMasterCustomerId = hist.ShipMasterCustomerId))
)
WHERE
(hist.ShipMasterCustomerId = '11115555')
AND
(hist.cycle_end_date = '2/29/2016')
Initially, I'll be storing all columns of source table to single variable using stored procedure(SP1). This SP1 is called inside SP2 and that variable is inserted into destination table.
I know the approach but stuck in implementing it.
-- SP1
Create procedure insert_data
AS
Declare #data nvarchar(60)
Begin
EXEC get
--Here i have to insert
END
Go
--SP2
Create procedure get_column
AS
Declare
#e_id int , #e_name nvarchar(20) , #d_id int,#res nvarchar(50)
Begin
SET #e_id =(select Emp_ID from Dim_Employee where Emp_Name='Cathy');
SET #e_name =(select Emp_Name from Dim_Employee where emp_id=101);
SET #d_id =(select Dept_ID from Dim_Employee where emp_name='Cathy');
SET #res ='#e_id , #e_name , #d_id';
return #res
END
Go
if you already have destination table:
insert into DestTbl(emp_id, dept_id, ...)
select emp_id, dept_id, ...
from Dim_Employee d
where ...
if you dont and wish to create it
select emp_id, dept_id, ...
into DestTbl
from Dim_Employee d
where ...
if you still want to use variables
insert into DestTbl(emp_id, dept_id)
values (#emp_id, #dept_id, ...)
is this what you're asking for?
INSERT statement on msdn:
https://technet.microsoft.com/en-us/library/ms174335.aspx
I have created a trigger for a asset_verification. Whenever a new record is inserted in this table, the same record is inserted in the asset_verification_history table because of this trigger.
The trigger is as follows
Create trigger [dbo].[tr_insert_after_asset_verification] on [dbo].[asset_verification]
for insert
As
Begin
declare #verification_id int
declare #id int
declare #audit_id int
declare #date date
declare #status varchar(15)
declare #remarks varchar(200)
declare #creationDate datetime
declare #modificationDate datetime
declare #updatedBy int
declare #audit_action varchar(20)
Select #verification_id = i.verification_id from inserted i
If #verification_id IS NOT NULL
Begin
Select #id = i.id from inserted i
Select #audit_id = i.audit_id from inserted i
Select #date = i.date from inserted i
Select #status = i.status from inserted i
Select #remarks = i.remarks from inserted i
Select #creationDate = i.creationDate from inserted i
Select #modificationDate = i.modificationDate from inserted i
Select #updatedBy = i.updatedBy from inserted i
set #audit_action = 'Insert Record'
INSERT INTO [dbo].[asset_verification_history]
([verification_id]
,[id]
,[audit_id]
,[date]
,[status]
,[remarks]
,[creationDate]
,[modificationDate]
,[updatedBy]
,[audit_action])
VALUES
(#verification_id
,#id
,#audit_id
,#date
,#status
,#remarks
,#creationDate
,#modificationDate
,#updatedBy
,#audit_action)
End
End
When I insert the data in the asset_verification table using a procedure in which OPEN XML is used, then this trigger works only for the first record. For the rest of the records the trigger doesn't work
The procedure is as follows
Create procedure [dbo].[usp_AddVerificationBulkData]
(
#vXML XML
)
As
Begin
DECLARE #DocHandle INT
SET NOCOUNT ON
EXEC sp_xml_preparedocument #DocHandle OUTPUT, #vXML
Update asset_verification
set
audit_id = x.AuditId,
id = x.SerialId,
date = x.VerificationDate,
status = x.Status
,remarks = x.Remarks
,creationDate = x.CreatedOn
,modificationDate = x.ModifiedOn
,updatedBy = x.ModifiedBy
From
asset_verification a
Inner Join
OpenXml(#DocHandle,'/ArrayOfAssetVerificationModel/AssetVerificationModel',2)
With(SerialId int, AuditId int, VerificationDate datetime, Status int, Remarks varchar(200), CreatedOn datetime, ModifiedOn datetime, ModifiedBy int) x
On a.audit_id = x.AuditId where a.id = x.SerialId;
INSERT INTO [dbo].[asset_verification]
([id]
,[audit_id]
,[date]
,[status]
,[remarks]
,[creationDate]
,[modificationDate]
,[updatedBy])
select SerialId,AuditId,VerificationDate,Status,Remarks,CreatedOn,ModifiedOn,ModifiedBy from OpenXml(#DocHandle,'/ArrayOfAssetVerificationModel/AssetVerificationModel',2)
With(SerialId int, AuditId int, VerificationDate datetime, Status int, Remarks varchar(200), CreatedOn datetime, ModifiedOn datetime, ModifiedBy int) x
where SerialId NOT IN (select a.id from asset_verification a where a.audit_id = x.AuditId);
End
Problem:- How to make this trigger work for every record that is inserted through Open XML ?
You've made the classic mistake of thinking that triggers fire once-per-row. They dont, it's once-per-action, so the inserted pseudo table holds all the rows affected by the action. Your trigger needs to work in a set based manner, not row based. Try this;
CREATE TRIGGER [dbo].[tr_insert_after_asset_verification] ON [dbo].[asset_verification] FOR INSERT AS
BEGIN
SET NOCOUNT ON
INSERT INTO [dbo].[asset_verification_history]
( [verification_id]
,[id]
,[audit_id]
,[date]
,[status]
,[remarks]
,[creationDate]
,[modificationDate]
,[updatedBy]
,[audit_action]
)
SELECT i.verification_id
,i.id
,i.audit_id
,i.date
,i.status
,i.remarks
,i.creationDate
,i.modificationDate
,i.updatedBy
,'Insert Record'
FROM inserted i
WHERE i.verification_id IS NOT NULL
END
As an aside, and strictly speaking, your original trigger will log one row, not necessarily the first.
I have a page on our intranet that submits requests to a perl CGI script. That script in turn calls a stored procedure on a SQL Server DB that check whether an object with certain attributes exists. If it does, the storproc returns the instrument's id, if it doesn't, it creates a new instrument and returns that new instrument's id. The stored procedure creates a transaction, and also uses with (TABLOCKX) in the insert statement. For user-friendliness, when said user submits a bunch of requests simultaneously, the web pages submits the requests to the perl script asynchronously. I thought that when several requests are submitted that all require a new instrument, the first one to hit the storproc would run, lock the table, create the new instrument, release the lock, and then the subsequent calls to the storproc would be aware of the new instrument and use that. What I saw in practice was that there would be a couple of requests that create the new instrument, and the rest would use the most recent one. I tried using a setTimeout on the client side to space out the requests, but that doesn't seem to make a difference. Any ideas as to what I may be doing wrong?
Here is the code of the stored procedure:
CREATE PROCEDURE [dbo].[CreateFutures]
#code varchar(5),
#month int,
#year int,
#currency varchar(3)
AS
BEGIN
SET NOCOUNT ON;
BEGIN TRANSACTION
declare #ticker varchar(7)
declare #yearCode char(1)
declare #res as Table (id int)
declare #n as int
set #yearCode = convert(char(1), #year % 10)
set #ticker = (
select #code + futures + #yearCode
from FuturesMonthCodes
where month = #month
)
insert into #res
select top 1 instrument
from InstrumentFutures // This is a view that joins InstrumentText and InstrumentNumber data
where ticker = #ticker
and code = #code
and month = #month
and year = #year
and currency = #currency
order by instrument
set #n = (select COUNT(id) from #res)
if #n = 0
begin
print 'Creating Future'
declare #id int
declare #stamp datetime
set #stamp = CURRENT_TIMESTAMP
insert into Instrument with (TABLOCKX) (insertTime) values (#stamp)
set #id = (select SCOPE_IDENTITY());
insert into InstrumentText (instrumentId, name, value) values (#id, 'type', 'futures')
insert into InstrumentText (instrumentId, name, value) values (#id, 'ticker', #ticker)
insert into InstrumentText (instrumentId, name, value) values (#id, 'code', #code)
insert into InstrumentText (instrumentId, name, value) values (#id, 'currency',#currency)
insert into InstrumentNumber (instrumentId, name, value) values (#id, 'month', #month)
insert into InstrumentNumber (instrumentId, name, value) values (#id, 'year', #year)
insert into #res (id) values (#id)
end
commit transaction
if #n = 0 --instrument created
select top 1 id, 1 from #res order by id
else --returning existing instrument
select top 1 id, 0 from #res order by id
END
It is more sql problem than perl.
Let say 3 scripts try to run this stored proc in the same time.
The first execute and it is locked the table. The others waited for the table to unlock but they not reread the data when the locking is over so they used old data.
If your stored proc make a select you have to rerun it after the locking are gone.
Regards,