Как передать вывод процедуры в многострочный оператор вставки - PullRequest
0 голосов
/ 11 февраля 2012

Учитывая следующий вызов процедуры, который возвращает управляемое приложением уникальное целое число:

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')

Тем не менее, это может быть немного зловещим, когда вы выводите 2 или более строк, как я сделал здесь:

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');

Неужели должен быть более эффективный способ?

Вот процедура получения следующего идентификатора:

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

основываясь на ответе ниже, реализовали:

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;

1 Ответ

1 голос
/ 11 февраля 2012

Во-первых, у вас должна быть таблица чисел (некоторый фон, который я написал здесь и здесь ).Я выбираю 100 000 строк, но вам может понадобиться больше или меньше, в зависимости от того, сколько вы собираетесь его использовать.

CREATE TABLE dbo.Numbers(n INT PRIMARY KEY);

INSERT dbo.Numbers(n) 
    SELECT TOP (100000) n = ROW_NUMBER()
     OVER (ORDER BY s1.[object_id])
FROM sys.all_objects AS s1
CROSS JOIN sys.objects AS s2;

Теперь вы можете просто сказать (я просто выбираю 10произвольно):

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 [GUID], 296563, 3961644, 'new test' + CONVERT(VARCHAR(12), n)
    FROM dbo.Numbers
    WHERE n >= @id AND n < @id + @num_ids;

Если вы считаете, что он возвращает правильный набор, раскомментируйте строку --INSERT.Только не сходите с ума, потому что вы исчерпываете их количество идентификаторов.


Извините, материал под этой строкой был написан с предположением, что вы использовали уникальные идентификаторы, как первоначально указывалось в вашем вопросе, а нецелые числа.Оставьте его на тот случай, если он будет полезен другим.

Если вы создаете хранимую процедуру, которая может генерировать несколько идентификаторов GUID, представьте себе, что эта процедура возвращает набор идентификаторов GUID:

CREATE PROCEDURE dbo.i13_get_multi_ids
AS
BEGIN
    SET NOCOUNT ON;

    -- application management magic here

    SELECT [GUID] = GuidValues FROM somewhere;
END
GO

Тогда вы могли бы сделать:

CREATE TABLE #f([GUID] UNIQUEIDENTIFIER);

INSERT #f EXEC dbo.i13_get_multi_ids;

INSERT dbo.TBL_LOCATIONS(objectid, X_Coord, Y_Coord, Loc_name)
SELECT [GUID], 296563, 3961644, 
   'new test' + CONVERT(VARCHAR(12), ROW_NUMBER() OVER (ORDER BY [GUID])) 
FROM #f ORDER BY [GUID];
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...