从存储过程结果集中插入/更新表上的数据

时间:2011-06-01 07:46:15

标签: sql sql-server-2008 stored-procedures loops

我有一个名为proc_item的存储过程,它从不同的表中获取数据(使用join)。我希望在另一个名为Item的表中插入存储过程的结果集(如果数据是新的)或更新(如果数据已存在)。任何人都可以告诉我如何做到这一点?我是sql,存储过程和循环的新手。

感谢

3 个答案:

答案 0 :(得分:8)

您应创建一个临时表来保存存储过程的结果,然后将结果合并到表中。建议使用临时表作为表变量,因为它会更好地加入现有表,因为有更好的统计数据。

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

OR:

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

答案 1 :(得分:2)

看看@srutzky的解决方案,它更适合这个问题


您可以做的第一件事就是将所有内容写入表中。 为此,您需要定义一个表,该表与存储过程返回的列具有相同的列:

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

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

现在您需要的所有数据都在表格中。下一步是检查您需要更新的内容以及要插入的内容。假设datarow1是用于检查它是否已经存在的变量(例如:相同的名称或相同的id) AND 让我们说它是唯一的(否则你还需要一些独特的东西 - 迭代所需的东西临时表)

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的解决方案没有光标):Cursor inside cursor

答案 2 :(得分:1)

首先需要将数据插入临时容器,如临时表或表变量。然后你可以像往常一样使用表:加入它,从中导出结果集等。

检查this question以获取将SP的输出存储到表中的选项。