вставка / обновление данных в таблице из набора результатов хранимых процедур - PullRequest
5 голосов
/ 01 июня 2011

У меня есть хранимая процедура proc_item, которая извлекает данные из разных таблиц (используя соединение). Я хочу, чтобы набор результатов из хранимой процедуры был вставлен (если данные новые) или обновлен (если данные уже существуют) в другую таблицу с именем Item. Кто-нибудь может дать мне некоторое представление о том, как я могу это сделать? Я новичок в SQL, хранимые процедуры и циклы.

спасибо

Ответы [ 3 ]

8 голосов
/ 01 июня 2011

Вы должны создать временную таблицу для хранения результатов сохраненного процесса, а затем объединить результаты в вашу таблицу.Временная таблица рекомендуется для переменной таблицы, так как она будет лучше присоединяться к существующей таблице благодаря лучшей статистике.

CREATE TABLE #TempResults
(
  Field1 DATATYPE1,
  Field2 DATATYPE2,
  ...,
  PRIMARY KEY CLUSTERED (KeyField1,...)
)

INSERT INTO #TempResults (Field1, Field2, ...)
   EXEC Schema.ProcName @Param1, ...

Теперь есть два способа слияния.Первый работает во всех версиях SQL Server, а второй использует команду, которая была введена в SQL Server 2008.

-- this should work on all SQL SERVER versions
UPDATE  rt
SET     rt.Field2 = tmp.Field2,
        ...
FROM    Schema.RealTable rt
INNER JOIN   #TempResults tmp
        ON   tmp.KeyField1 = rt.KeyField1
        ...

INSERT INTO Schema.RealTable (Field1, Field2, ...)
   SELECT  tmp.Field1, tmp.Field2, ...
   FROM    #TempResults tmp
   LEFT JOIN  Schema.RealTable rt
          ON  rt.KeyField1 = tmp.KeyField1
          ...
   WHERE   rt.KeyField1 IS NULL

ИЛИ:

-- the MERGE command was introduced in SQL SERVER 2008
MERGE Schema.RealTable AS target
USING (SELECT Field1, Field2,... FROM #TempResults) AS source (Field1, Field2,..)
ON (target.KeyField1 = source.KeyField1)
WHEN MATCHED THEN 
  UPDATE SET Field2 = source.Field2,
         ...
WHEN NOT MATCHED THEN   
  INSERT (Field1, Field2,...)
     SELECT  tmp.Field1, tmp.Field2, ...
     FROM    #TempResults tmp

Для получения дополнительной информации о команде MERGE, перейдите сюда:
http://msdn.microsoft.com/en-us/library/bb510625(v=SQL.100).aspx

Теперь, если у вас большой набор результатов для слияния, а таблица, в которую вы объединяетесь, очень большая и в ней много операций, где используется этот тип операцийможет вызвать некоторую блокировку, тогда она может быть зациклена для выполнения наборов по 1000 строк за раз или что-то в этом роде.Что-то вроде этого:

<insert CREATE TABLE / INSERT...EXEC block>

CREATE TABLE #CurrentBatch
(
  Field1 DATATYPE1,
  Field2 DATATYPE2,
  ...
)

DECLARE @BatchSize SMALLINT = ????

WHILE (1 = 1)
BEGIN

    -- grab a set to work on
    DELETE TOP (@BatchSize)
    OUTPUT deleted.Field1, deleted.Field2, ...
    INTO #CurrentBatch (Field1, Field2, ...)
    FROM #TempResults

    IF (@@ROWCOUNT = 0)
    BEGIN
        -- no more rows
        BREAK
    END

    <insert either UPDATE / INSERT...SELECT block or MERGE block from above
     AND change references to #TempResults to be #CurrentBatch>

    TRUNCATE TABLE #CurrentBatch

END
2 голосов
/ 01 июня 2011

Взгляните на решение @srutzky, которое больше подходит для этой проблемы


Первое, что вы можете сделать, это записать все в таблицу.Для этого вам нужно определить таблицу, в которой есть те же столбцы, что и в вашей хранимой процедуре:

DECLARE @myTempTableName TABLE(
                                dataRow1 DATATYPE,
                                dataRow2 DATATYPE,
                                ...
                               )

INSERT INTO @myTempTableName(dataRow1, dataRow2,...)
EXEC( *mystoredprocedure* )

Теперь все необходимые вам данные находятся в таблице.Следующий шаг - проверить, что нужно обновить и что вставить.Допустим, datarow1 - это переменная, которая проверяет, существует ли она уже или нет (например: то же имя или тот же идентификатор) И Допустим, она уникальна (в противном случае вам также нужно что-то уникальное, что необходимо для итерации повременная таблица)

DECLARE @rows INT,
        @dataRow1 DATATYPE,
        @dataRow2 DATATYPE, ...

-- COUNT Nr. of rows (how many rows are in the table)
SELECT 
    @rows = COUNT(1) 
FROM 
    @myTempTableName 

-- Loop while there are still some rows in the temporary table
WHILE (@rows > 0)

BEGIN

  -- select the first row and use dataRow1 as indicator which row it is. If dataRow1 is not unique the index should be provided by the stored procedure as an additional column
  SELECT TOP 1
    @dataRow1 = dataRow1,
    @dataRow2 = dataRow2, ..
  FROM
    @myTempTableName

  -- check if the value you'd like to insert already exists, if yes --> update, else --> insert
  IF EXISTS (SELECT * FROM *TableNameToInsertOrUpdateValues* WHERE dataRow1=@dataRow1)
      UPDATE 
            *TableNameToInsertOrUpdateValues*
      SET
            dataRow2=@dataRow2
      WHERE
            dataRow1=@dataRow1

  ELSE
      INSERT INTO 
            *TableNameToInsertOrUpdateValues* (dataRow1, dataRow2)
      VALUES 
            (@dataRow1, @dataRow2)


  --IMPORTANT: delete the line you just worked on from the temporary table
  DELETE FROM 
     @myTempTableName 
  WHERE 
     dataRow1= @dataRow1

  SELECT 
     @rows = COUNT(1) 
  FROM 
     @myTempTableName

END -- end of while-loop

Объявление можно сделать в начале этого запроса.Я положил его на то место, где я его использовал, чтобы его было легче читать.

Откуда я получил часть своего кода и также полезен для перебора таблиц (решение из @cmsjr без курсора): Курсор внутри курсора

1 голос
/ 01 июня 2011

Сначала необходимо вставить данные во временный контейнер, например, во временную таблицу или переменную таблицы.Затем вы можете работать с таблицей, как обычно: присоединиться к ней, извлечь из нее наборы результатов и т. Д.

Проверить этот вопрос , чтобы узнать, как сохранить выходные данные SP в таблицу.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...