我该如何做一个Upsert表格?


3

我有一个视图,其中包含作业列表,其中包含分配给他们的人员以及他们所处的阶段等数据。我需要编写一个存储过程,以返回每个人每个阶段有多少作业。

到目前为止,我有这个(简体):

DECLARE @ResultTable table 
(
    StaffName nvarchar(100), 
    Stage1Count int, 
    Stage2Count int 
) 

INSERT INTO @ResultTable (StaffName, Stage1Count) 
    SELECT StaffName, COUNT(*) FROM ViewJob 
    WHERE InStage1 = 1 
    GROUP BY StaffName 

INSERT INTO @ResultTable (StaffName, Stage2Count) 
    SELECT StaffName, COUNT(*) FROM ViewJob 
    WHERE InStage2 = 1 
    GROUP BY StaffName 

但问题是,行不合并。所以如果一个职员在stage1和stage2中有工作,那么@ResultTable中有两行。我真正想做的是更新该行(如果存在该职员)并插入新行(如果该行不存在)。

有谁知道如何做到这一点,或者可以建议一种不同的方法? 我真的想避免使用游标迭代用户列表(但这是我的回退选项)。

我使用的是SQL Server 2005中

编辑:@Lee:不幸的是,InStage1 = 1是一个简化。它更像是WHERE DateStarted IS NOT NULL和DateFinished IS NULL。

编辑:@BCS:我喜欢先插入所有员工,所以我只需要每次都做一次更新。但我努力让这些UPDATE语句正确。

1

IIRC有某种“我国重复”(名称可能是错误的)语法,可以让你更新,如果一个行存在(MySQL的)

或者某种形式的:

INSERT INTO @ResultTable (StaffName, Stage1Count, Stage2Count) 
    SELECT StaffName,0,0 FROM ViewJob 
    GROUP BY StaffName 

UPDATE @ResultTable Stage1Count= (
    SELECT COUNT(*) AS count FROM ViewJob 
    WHERE InStage1 = 1 
    @ResultTable.StaffName = StaffName) 

UPDATE @ResultTable Stage2Count= (
    SELECT COUNT(*) AS count FROM ViewJob 
    WHERE InStage2 = 1 
    @ResultTable.StaffName = StaffName) 
+1

您提到的“一式两份”是INSERT ...在DUPLICATE KEY UPDATE上,文档位于:http://dev.mysql.com/doc/refman/5.0/en/insert-on-duplicate.html 14 10月. 082008-10-14 02:16:11


1

要获得真正的“upsert”类型的查询,您需要使用if exists ...类型的东西,而这不幸意味着使用游标。

但是,您可以运行两个查询,一个用于在存在现有行的情况下执行更新,然后插入新查询。我认为这种基于集合的方法会更好,除非你专门处理少量的行。


2

您可以检查是否存在并使用相应的命令。我相信,这确实在后台使用游标,但它是最好的,你可能会得到:

IF (EXISTS (SELECT * FROM MyTable WHERE StaffName = @StaffName)) 
begin 
    UPDATE MyTable SET ... WHERE StaffName = @StaffName 
end 
else 
begin 
    INSERT MyTable ... 
end 

SQL2008有一个新的MERGE能力这是很酷,但它不是在2005年


3

其实,我认为你做得比现在更困难。这段代码不会适用于你想要做的事情吗?

SELECT StaffName, SUM(InStage1) AS 'JobsAtStage1', SUM(InStage2) AS 'JobsAtStage2' 
    FROM ViewJob 
GROUP BY StaffName 

0

对结果表的以下查询应该再次组合行。这是假设InStage1和InStage2从来都不是'1'。

select distinct(rt1.StaffName), rt2.Stage1Count, rt3.Stage2Count 
from @ResultTable rt1 
left join @ResultTable rt2 on rt1.StaffName=rt2.StaffName and rt2.Stage1Count is not null 
left join @ResultTable rt3 on rt1.StaffName=rt2.StaffName and rt3.Stage2Count is not null 

0

我设法让它与BCS的答案的变体一起工作。它不会让我使用表变量,所以我不得不做一个临时表。

CREATE TABLE #ResultTable 
(
    StaffName nvarchar(100), 
    Stage1Count int, 
    Stage2Count int 
) 

INSERT INTO #ResultTable (StaffName) 
    SELECT StaffName FROM ViewJob 
    GROUP BY StaffName 

UPDATE #ResultTable SET 
    Stage1Count= (
    SELECT COUNT(*) FROM ViewJob V 
    WHERE InStage1 = 1 AND 
     V.StaffName = @ResultTable.StaffName COLLATE Latin1_General_CI_AS 
    GROUP BY V.StaffName), 
    Stage2Count= (
    SELECT COUNT(*) FROM ViewJob V 
    WHERE InStage2 = 1 AND 
     V.StaffName = @ResultTable.StaffName COLLATE Latin1_General_CI_AS 
    GROUP BY V.StaffName) 

SELECT StaffName, Stage1Count, Stage2Count FROM #ResultTable 

DROP TABLE #ResultTable