简体   繁体   English

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

[英]inserting/updating data on table from a stored procedure result set

I've a stored procedure called proc_item that fetches data from different tables (using join).我有一个名为 proc_item 的存储过程,它从不同的表中获取数据(使用连接)。 I want the result set from the stored procedure to be either inserted (if the data is new) or updated (if the data already exists) on another table called Item.我希望将存储过程的结果集插入(如果数据是新的)或更新(如果数据已经存在)到另一个名为 Item 的表上。 Can anybody give me some idea as to how i can do this?任何人都可以给我一些关于我如何做到这一点的想法吗? I'm new to sql, stored procedures and looping.我是 sql、存储过程和循环的新手。

thanks谢谢

You should create a Temporary Table to hold the results of the Stored Proc and then merge the results into your table.您应该创建一个临时表来保存存储过程的结果,然后将结果合并到您的表中。 A Temporary Table is recommended over a Table Variable as it will JOIN better to the existing Table due to better statistics.建议使用临时表而不是表变量,因为由于更好的统计信息,它将更好地连接到现有表。

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

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

Now, there are two ways to do the merge.现在,有两种方法可以进行合并。 The first works in all versions of SQL Server and the second uses a command that was introduced in SQL Server 2008.第一个适用于 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

For more information on the MERGE command, go here:有关 MERGE 命令的更多信息,请在此处查看 go:
http://msdn.microsoft.com/en-us/library/bb510625(v=SQL.100).aspx http://msdn.microsoft.com/en-us/library/bb510625(v=SQL.100).aspx

Now, if you have a large result set to merge and the table you are merging into is very large and has a lot of activity on it where this type of operation might cause some blocking, then it can be looped to do sets of 1000 rows at a time or something like that.现在,如果您有一个大的结果集要合并,并且您要合并到的表非常大并且上面有很多活动,而这种类型的操作可能会导致一些阻塞,那么它可以循环执行 1000 行的集合一次或类似的事情。 Something along the lines of this:类似这样的东西:

<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

Take a look at @srutzky 's solution which is more appropriate to this problem看看@srutzky 更适合这个问题的解决方案


The first thing you could do is write everything into a table.您可以做的第一件事是将所有内容写入表格。 To do so, you need to define a table, which has the same columns as they are returned by your stored procedure:为此,您需要定义一个表,该表具有与存储过程返回的列相同的列:

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

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

Now all the data you need is in the table.现在您需要的所有数据都在表中。 Next step is to check what you need to update and what to insert.下一步是检查您需要更新的内容和插入的内容。 Let's say datarow1 is the variable to check if it already exists or not (for example: same name or same id) AND let's say it's unique (else you need also something witch is unique - needed for iterating through the temporary table)假设 datarow1 是检查它是否已经存在的变量(例如:相同的名称或相同的 id)并且假设它是唯一的(否则您还需要一些独特的东西 - 需要遍历临时表)

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

The declaration can be done, at the beginning of this Query.可以在此查询的开头进行声明。 I put it on the place where I used it so that it's easier to read.我把它放在我使用它的地方,这样更容易阅读。

Where I got part of my Code from and also helpful for iterating through tables (solution from @cmsjr without cursor): Cursor inside cursor我从哪里获得了我的部分代码,也有助于遍历表(来自@cmsjr 的无光标解决方案): Cursor inside cursor

You need first to insert the data into a temporary container, like a temporary table or a table variable.您需要首先将数据插入到临时容器中,例如临时表或表变量。 Then you can work with the table as usual: join it, derive result sets from it etc.然后您可以像往常一样使用该表:加入它,从中派生结果集等。

Check this question for the options for storing the output of an SP into a table.检查此问题以获取将 SP 的 output 存储到表中的选项。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM