March 22, 2004 at 3:40 pm
I am trying to come up with a way to handle duplicate keys on a batch insert without failing. I'd like to handle this within the DBMS. One way we do this now is a bulk insert into an unrelated working table and then insert into the production table the difference between the working table and the production table. I was wondering if triggers could be used to do a similiar operation. I created the example below which only seems to do one or the other i.e. log the dups or insert the unique rows, but it won't do both why?
if exists (select * from sysobjects where id = object_id(N'[dbo].[bkiTriggerTest]') and OBJECTPROPERTY(id, N'IsUserTable') = 1)
drop table [dbo].[bkiTriggerTest]
GO
if exists (select * from sysobjects where id = object_id(N'[dbo].[bkiTriggerTestDups]') and OBJECTPROPERTY(id, N'IsUserTable') = 1)
drop table [dbo].[bkiTriggerTestDups]
GO
--
Create table dbo.bkiTriggerTest
(
pkid int identity(1,1) not null,
dval1 numeric(22,0) default(0),
dval2 nvarchar(4000) default(N'Variable length text field'),
Constraint bkiTriggerTest_PK Primary Key Clustered (pkid),
) ON [Primary]
go
Create table dbo.bkiTriggerTestDups
(
pkid int not null,
dval1 numeric(22,0) default(0),
dval2 nvarchar(4000) default(N'Variable length text field'),
) ON [Primary]
go
if exists (select * from sysobjects where id = object_id(N'[dbo].[bkiTriggerTest_Instead]') and OBJECTPROPERTY(id, N'ExecIsInsteadOfTrigger') = 1)
drop trigger [dbo].[bkiTriggerTest_Instead]
GO
Create trigger dbo.bkiTriggerTest_Instead
on dbo.bkiTriggerTest
INSTEAD OF INSERT
AS
set nocount on
insert into dbo.bkiTriggerTestDups (i2.pkid, i2.dval1, i2.dval2)
select i2.pkid, i2.dval1, i2.dval2
from Inserted i2 inner join dbo.bkiTriggerTest base
on i2.pkid = base.pkid
insert into dbo.bkiTriggerTest (pkid, dval1, dval2)
select pkid, dval1, dval2
from Inserted i
where not exists
(select i2.pkid from Inserted i2 inner join dbo.bkiTriggerTest base
on i2.pkid = base.pkid
)
go
-------------------------------
set identity_insert bkiTriggerTest ON
insert into dbo.bkiTriggerTest (pkid, dval1, dval2)
values( 1, 1, N'Test insert 1')
go
-- contents of bki.dat
-- 4, 4, N'Record 4'
-- 2, 2, N'Record 2'
-- 3, 3, N'Record 3'
--
bulk insert dbo.bkiTriggerTest from 'h:\temp\bki.dat'
with (DATAFILETYPE='char',
KEEPIDENTITY,
FIELDTERMINATOR = ',',
ROWTERMINATOR ='\n',
FIRE_TRIGGERS)
go
select * from dbo.bkiTriggerTest
select * from dbo.bkiTriggerTestDups
go
-- contents of bki2.dat
-- 4, 4, N'Record 4'
-- 2, 2, N'Record 2'
-- 6, 6, N'Record 6'
--
bulk insert dbo.bkiTriggerTest from 'h:\temp\bki2.dat'
with (DATAFILETYPE='char',
KEEPIDENTITY,
FIELDTERMINATOR = ',',
ROWTERMINATOR ='\n',
FIRE_TRIGGERS)
go
select * from dbo.bkiTriggerTest
select * from dbo.bkiTriggerTestDups
go
March 22, 2004 at 5:24 pm
David,
Just use if @@rowcount = 0 condition in your instead of insert trigger just before the actual table insert statement. This will avoid failing statements as well as log the desired duplicates as you coded.
Gopal
March 23, 2004 at 12:24 am
Little error in your trigger. Please try this :
Create trigger dbo.bkiTriggerTest_Instead
on dbo.bkiTriggerTest
INSTEAD OF INSERT
AS
set nocount on
insert into dbo.bkiTriggerTestDups (i2.pkid, i2.dval1, i2.dval2)
select i2.pkid, i2.dval1, i2.dval2
from Inserted i2 inner join dbo.bkiTriggerTest base
on i2.pkid = base.pkid
insert into dbo.bkiTriggerTest (pkid, dval1, dval2)
select pkid, dval1, dval2
from Inserted i
where i.pkid not in
(select i2.pkid from Inserted i2 inner join dbo.bkiTriggerTestDups base
on i2.pkid = base.pkid
)
March 23, 2004 at 11:22 am
Gopal (ext5qxt)
If I test for @@ROWCOUNT equal to zero, then I won't execute the second insert when there are dups. But I want to execute both statements because there may be some dups and some not.
Thanks, Dave
March 23, 2004 at 11:26 am
Grasshopper,
Ahh! I couldn't see it for anything. What I meant was not what I typed. I wanted the difference like what follows:
Create trigger dbo.bkiTriggerTest_Instead
on dbo.bkiTriggerTest
INSTEAD OF INSERT
AS
set nocount on
insert into dbo.bkiTriggerTestDups (i2.pkid, i2.dval1, i2.dval2)
select i2.pkid, i2.dval1, i2.dval2
from Inserted i2 inner join dbo.bkiTriggerTest base
on i2.pkid = base.pkid
insert into dbo.bkiTriggerTest (pkid, dval1, dval2)
select pkid, dval1, dval2
from Inserted i
where not exists
-- where i.pkid not in
(select i2.pkid from Inserted i2 inner join dbo.bkiTriggerTest base
on i.pkid = base.pkid
)
(Hmmm. It looks strange to me with the 92 join syntax, but I guess logically it should be the same.)
Thanks, Dave
March 23, 2004 at 11:39 am
CHECK IT OUT
Create trigger dbo.bkiTriggerTest_Instead
on dbo.bkiTriggerTest
INSTEAD OF INSERT
AS
-- TRIGGER GETS CALLED FOR EVERY INSERT STATEMENT. ONE ROW AT A TIME
set nocount on
insert into dbo.bkiTriggerTestDups (i2.pkid, i2.dval1, i2.dval2)
select i2.pkid, i2.dval1, i2.dval2
from Inserted i2 inner join dbo.bkiTriggerTest base
on i2.pkid = base.pkid
-- INSERT ONLY IF THERE IN NO DUPLICATE
IF @@ROWCOUNT = 0
insert into dbo.bkiTriggerTest (pkid, dval1, dval2)
select pkid, dval1, dval2
from Inserted i
/* YOU DO NOT NEED THIS CONDITION. AS IT IS INSTEAD OF TRIGGER.
where not exists
-- where i.pkid not in
(select i2.pkid from Inserted i2 inner join dbo.bkiTriggerTest base
on i.pkid = base.pkid
)
*/
Viewing 6 posts - 1 through 5 (of 5 total)
You must be logged in to reply to this topic. Login to reply