Wie führe ich einen Upsert in die Tabelle?


3

Ich habe eine Ansicht, die eine Liste von Jobs enthält, mit Daten wie, wem sie zugeordnet sind und die Bühne, in der sie sind. Ich muss eine gespeicherte Prozedur schreiben, die zurückgibt, wie viele Jobs jede Person in jeder Phase hat.

Bisher habe ich diese (vereinfacht):

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 

Das Problem dabei ist, dass die Zeilen nicht kombinieren. Wenn ein Mitarbeiter also Jobs in stage1 und stage2 hat, gibt es zwei Zeilen in @ResultTable. Was ich wirklich gerne tun würde, ist, die Zeile zu aktualisieren, falls eine für den Mitarbeiter existiert, und eine neue Zeile einzufügen, falls eine nicht existiert.

Weiß jemand, wie man das macht, oder kann man einen anderen Ansatz vorschlagen? Ich würde wirklich gerne vermeiden, Cursor zu verwenden, um auf der Liste der Benutzer zu iterieren (aber das ist meine Fallback-Option).

Ich bin mit SQL Server 2005.

Edit: @Lee: Leider ist der InStage1 = 1 war eine Vereinfachung. Es ist wirklich mehr wie WHERE DateStarted ist nicht NULL und DateFinished ist NULL.

Bearbeiten: @BCS: Ich mag die Idee, eine Einfügung aller Mitarbeiter zuerst, so dass ich nur ein Update jedes Mal tun müssen. Aber ich habe Mühe, diese UPDATE-Anweisungen zu korrigieren.

1

IIRC gibt es eine Art von "On Duplizieren" (Name könnte falsch sein) Syntax, die Sie aktualisieren können, wenn eine Zeile vorhanden ist (MySQL)

Alternativ irgendeine Form von:

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

die "auf doppelte", die Sie erwähnen, ist INSERT ...ON DUPLICATE KEY UPDATE und die Dokumentation finden Sie hier: http://dev.mysql.com/doc/refman/5.0/en/insert-on-duplicate.html 14 okt. 082008-10-14 02:16:11


1

Um eine echte "upsert" -Art der Abfrage zu erhalten, müssen Sie eine if exists ... Art der Sache verwenden, und dies bedeutet leider, einen Cursor zu verwenden.

Sie können jedoch zwei Abfragen ausführen, eine für Ihre Aktualisierungen, bei der eine vorhandene Zeile vorhanden ist, und anschließend die neue Zeile. Ich würde denken, dass dieser Set-basierte Ansatz vorzuziehen wäre, es sei denn, Sie beschäftigen sich ausschließlich mit kleinen Reihen.


2

Sie könnten einfach auf Existenz prüfen und den entsprechenden Befehl verwenden. Ich glaube, das macht wirklich einen Cursor hinter den Kulissen verwenden, aber es ist das Beste, Sie werden wahrscheinlich erhalten:

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

SQL2008 hat eine neue MERGE Fähigkeit, die cool ist, aber es ist nicht im Jahr 2005.


3

Eigentlich Ich denke du machst es viel schwieriger als es ist. Funktioniert dieser Code nicht für das, was Sie versuchen?

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

0

Die folgende Abfrage in Ihrer Ergebnistabelle sollte die Zeilen erneut kombinieren. Dies setzt voraus, dass InStage1 und InStage2 niemals beide "1" sind.

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

Ich habe es geschafft, es mit einer Variation von BCS Antwort arbeiten zu lassen. Es würde mich jedoch nicht erlauben, eine Tabellenvariable zu verwenden, also musste ich eine temporäre Tabelle erstellen.

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