我有一个名为proc_item的存储过程,它从不同的表中获取数据(使用join)。我希望在另一个名为Item的表中插入存储过程的结果集(如果数据是新的)或更新(如果数据已存在)。任何人都可以告诉我如何做到这一点?我是sql,存储过程和循环的新手。
感谢
答案 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)
您可以做的第一件事就是将所有内容写入表中。 为此,您需要定义一个表,该表与存储过程返回的列具有相同的列:
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的输出存储到表中的选项。