April 7, 2004 at 1:53 pm
I have a table as shown below whose primary key is an identity. I want to have a stored procedure that will either insert or update one row and return the identity. The following stored procedure works but is it a good and effective way to solve the problem? Thanks in advance for your help, Pete
CREATE TABLE [dbo].[Alert] (
[AlertID] [int] IDENTITY ,
[AlertDate] [datetime] NOT NULL ,
[Source] [varchar] (50) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL ,
[IncidentNo] [varchar] (50) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL ,
[Severity] [int] NOT NULL ,
[Processed] [int] DEFAULT 0,
[Purged] [int] DEFAULT 0,
[Category] [varchar] (20) COLLATE SQL_Latin1_General_CP1_CI_AS NULL ,
[Text] [varchar] (250) COLLATE SQL_Latin1_General_CP1_CI_AS NULL ,
[varchar] (250) COLLATE SQL_Latin1_General_CP1_CI_AS NULL
) ON [PRIMARY]
GO
CREATE PROCEDURE dbo.xp_insAlert
@source varchar(50),
@IncidentNo varchar(50),
@Severity int,
@Category varchar(50),
@AlertText varchar(250),
@url varchar(250),
@alertNumber int OUT
AS
set @alertNumber = (select alertid from alert where source = @source and IncidentNo = @IncidentNo)
if @alertNumber is null
begin
insert into alert (alertDate,source,incidentNo,severity,category,text,url)
values(current_timestamp,@Source,@IncidentNo,@Severity,@Category,@AlertText,@url)
set @alertNumber = scope_identity()
end
else
begin
update alert set text = @alertText where alertID = @alertNumber
end
GO
April 8, 2004 at 1:22 am
This seems OK to me . You could add begin/commit transaction to make sure you do not insert the same source and IncidentNo twice. You probably also want a (clustered) PRIMARY KEY on source and IncidentNo.
April 8, 2004 at 10:45 pm
1. The name prefix xp_ is typically used for extended stored procs (not written in T-SQL), I would not use it here.
2. After AS, add "set nocount on" line
3. I assume there is a unique constraint on source, IncidentNo ?
3. Is it possible to get near simultaneous inserts on same (source, IncidentNo)? If so consider adding tran around the "existence check" (set @AlertNumber = (select alertid...)) and the insert/update, and adding UPDLOCK to the "existence check."
4. Do you care if inserts or updates fail? If so, need to check @@error & then act on it
select @err = @@error
if (@err <> 0) ...
5. Here's transaction & error code structure (we avoid beginning/ending tran if we're already in one, and never know if calling proc/app has already begun a tran or not, so we check):
declare @InitialTranCount int
set @InitialTranCount = @@trancount
if @InitialTranCount = 0
begin tran
set @alertNumber = (select alertid from alert(UPDLOCK) where source = @source and IncidentNo = @IncidentNo)
...insert/update...
select @err = @@error
if (@err <> 0)
begin
...do something, maybe raiserror()
if (@@trancount > @InitialTranCount)
rollback
end
--success
if (@@trancount > @InitialTranCount)
commit
PS - Started this before I saw Bert's reply--I duplicated some of his comments, sorry.
PS - I never use the "set @var = (select ...)" syntax, seemed like extra typing to me, have used "select @var = ..." syntax. But I just learned here that the set syntax has side-benefit of initializing @var to NULL if (select ...) returns nothing. Nice to know.
April 9, 2004 at 7:36 am
What I feel is First rin the update statement statement as
update alert set text = @alertText where alertID = ( select alertid from alert where source = @source and IncidentNo = @IncidentNo)
and checkfor the @@rowcount if it is greater than 0 there is no need to run the insert statement obviously, if its 0 get the @alertnumber and run the insert sql.
You may want to check this with real data and running the execution plan to see which is optimal.
Thanks
Prasad Bhogadi
www.inforaise.com
April 9, 2004 at 10:45 am
We do this type of thing quite often. However, if the record already exists, it is up to the caller to provide the ID. This avoids the select. We also always return the identity value to the caller:
CREATE PROCEDURE dbo.xp_insAlert
@source varchar(50),
@IncidentNo varchar(50),
@Severity int,
@Category varchar(50),
@AlertText varchar(250),
@url varchar(250),
@alertNumber int
AS
if @alertNumber is null
begin
insert into alert (alertDate,source,incidentNo,severity,category,text,url)
values(current_timestamp,@Source,@IncidentNo,@Severity,@Category,@AlertText,@url)
set @alertNumber = scope_identity()
-- Get the new identity value for the caller
select @alertNumber = @@identity
end
else
begin
update alert set text = @alertText where alertID = @alertNumber
end
return @alertNumber
GO
Viewing 5 posts - 1 through 4 (of 4 total)
You must be logged in to reply to this topic. Login to reply