Given the following procedure call which returns an application-managed unique integer:
DECLARE @id as integer
DECLARE @num_ids as integer
EXEC dbo.i13_get_ids 2, 1, @id output, @num_ids output
SELECT @id as N'@base_id'
I'm passing the result id onto an insert statement
insert into dbo.TBL_LOCATIONS (objectid, X_Coord, Y_Coord, Loc_Name)
values (@id,296163,3961644, 'new test')
However, that can be a bit ominous when iserting 2 or more rows, as I've done here:
DECLARE @id as integer
DECLARE @num_ids as integer
EXEC dbo.i13_get_ids 2, 1, @id output, @num_ids output
SELECT @id as N'@base_id';
insert into dbo.TBL_LOCATIONS (objectid, X_Coord, Y_Coord, Loc_Name)
values (@id,296163,3961644, 'new test');
EXEC dbo.i13_get_ids 2, 1, @id output, @num_ids output
SELECT @id as N'@base_id';
insert into dbo.TBL_LOCATIONS (objectid, X_Coord, Y_Coord, Loc_Name)
values (@id,296163,3961644, 'new test2');
EXEC dbo.i13_get_ids 2, 1, @id output, @num_ids output
SELECT @id as N'@base_id';
insert into dbo.TBL_LOCATIONS (objectid, X_Coord, Y_Coord, Loc_Name)
values (@id,296563,3961644, 'new test3');
Surely there has to be a more efficient way?
Here is the procedure that is retrieving the next ID:
GO
/****** Object: StoredProcedure [dbo].[i13_get_ids] ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE PROCEDURE [dbo].[i13_get_ids]
@id_type integer,
@num_requested_ids integer,
@base_id integer OUTPUT,
@num_obtained_ids integer OUTPUT AS SET NOCOUNT ON
BEGIN
IF (@num_requested_ids < 0)
BEGIN
BEGIN TRAN id_tran
/* We are resetting the generator. */
/* Delete fragments and update the base value.*/
UPDATE ATBI.DBO.i13 WITH (tablockx, holdlock)
SET base_id = base_id + @num_requested_ids
WHERE num_ids = -1 AND id_type = @id_type
DELETE FROM ATBI.DBO.i13 WHERE id_type = @id_type and num_ids <> -1
COMMIT TRAN id_tran /* releases holdlock table lock */
END
ELSE
BEGIN
IF (@num_requested_ids > 0)
BEGIN
DECLARE I_cursor CURSOR FOR
SELECT base_id, num_ids
FROM ATBI.DBO.i13 WITH (tablockx, holdlock)
WHERE id_type = @id_type
ORDER BY num_ids DESC /* ensures that fragments come first */
FOR UPDATE /* to get a lock */
END
ELSE
BEGIN
/* only interested in base id */
DECLARE I_cursor CURSOR FOR
SELECT base_id, num_ids
FROM ATBI.DBO.i13 WITH (tablockx, holdlock)
WHERE id_type = @id_type AND num_ids = -1
FOR UPDATE /* to get a lock */
END
BEGIN TRAN id_tran
OPEN I_cursor
FETCH NEXT FROM I_cursor INTO @base_id, @num_obtained_ids
IF (@num_requested_ids = 0)
BEGIN
/* Just getting current value */
SET @num_obtained_ids = 0
END
ELSE
BEGIN
IF (@num_obtained_ids = -1)
BEGIN
/* user got the amount they wanted */
SET @num_obtained_ids = @num_requested_ids
/* update the last id and base id */
UPDATE ATBI.DBO.i13
SET base_id = base_id + @num_obtained_ids,
last_id = @base_id
WHERE CURRENT OF I_cursor
END
ELSE
BEGIN
/* user got a fragment */
IF (@num_requested_ids = 1) AND (@num_obtained_ids > 1)
BEGIN
/* they want one and exactly one id */
SET @num_obtained_ids = 1
UPDATE ATBI.DBO.i13 SET base_id = base_id + 1,
num_ids = num_ids - 1 WHERE CURRENT OF I_cursor
END
ELSE
BEGIN
/* Return the whole fragment, delete the the row */
DELETE FROM ATBI.DBO.i13 WHERE CURRENT OF I_cursor
END
END
END
CLOSE I_cursor
COMMIT TRAN id_tran /* releases holdlock table lock */
DEALLOCATE I_cursor
END
END
GO
based on answer below, have implemented:
DECLARE @id INT, @num_ids INT;
EXEC [dbo].[i13_get_ids] 2, 10, @id OUTPUT, @num_ids OUTPUT;
INSERT dbo.TBL_Locations(objectid, X_Coord, Y_Coord, Loc_name)
SELECT N, 296563, 3961644, 'new test'
FROM dbo.oidNumbers WHERE n >= @id AND n < @id + @num_ids;