Come faccio a eseguire un Upsert nella tabella?
-
09-06-2019 - |
Domanda
Ho una vista che contiene un elenco di lavori, con dati come a chi sono assegnati e la fase in cui si trovano.Devo scrivere una procedura memorizzata che restituisca quanti lavori ha ciascuna persona in ogni fase.
Finora ho questo (semplificato):
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
Il problema è che le righe non si combinano.Pertanto, se un membro dello staff ha lavori in stage1 e stage2, ci sono due righe in @ResultTable.Quello che mi piacerebbe davvero fare è aggiornare la riga se ne esiste una per il membro dello staff e inserire una nuova riga se non ne esiste una.
Qualcuno sa come farlo o può suggerire un approccio diverso?Vorrei davvero evitare di utilizzare i cursori per scorrere l'elenco degli utenti (ma questa è la mia opzione di riserva).
Sto utilizzando SQL Server 2005.
Modificare:@Lee: Sfortunatamente InStage1 = 1 era una semplificazione.In realtà è più simile a DOVE DateStarted IS NULL e DateFinish IS NULL.
Modificare:@BCS: Mi piace l'idea di fare prima un inserto di tutto lo staff, quindi devo solo fare un aggiornamento ogni volta.Ma faccio fatica a ottenere quelle dichiarazioni UPDATE corrette.
Soluzione
IIRC esiste una sorta di sintassi "On Duplicate" (il nome potrebbe essere sbagliato) che ti consente di aggiornare se esiste una riga (MySQL)
In alternativa una qualche forma di:
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)
Altri suggerimenti
In realtà, penso che tu stia rendendo le cose molto più difficili di quanto non siano.Questo codice non funzionerà per quello che stai cercando di fare?
SELECT StaffName, SUM(InStage1) AS 'JobsAtStage1', SUM(InStage2) AS 'JobsAtStage2'
FROM ViewJob
GROUP BY StaffName
Potresti semplicemente verificarne l'esistenza e utilizzare il comando appropriato.Credo che questo utilizzi davvero un cursore dietro le quinte, ma è il meglio che probabilmente otterrai:
IF (EXISTS (SELECT * FROM MyTable WHERE StaffName = @StaffName))
begin
UPDATE MyTable SET ... WHERE StaffName = @StaffName
end
else
begin
INSERT MyTable ...
end
SQL2008 ha una nuova funzionalità MERGE che è interessante, ma non è nel 2005.
Per ottenere un vero tipo di query "upsert" è necessario utilizzare un se esiste...genere di cose, e questo sfortunatamente significa usare un cursore.
Tuttavia, potresti eseguire due query, una per eseguire gli aggiornamenti dove è presente una riga esistente, quindi successivamente inserire quella nuova.Penso che questo approccio basato su set sarebbe preferibile a meno che tu non abbia a che fare esclusivamente con un numero limitato di righe.
La seguente query sulla tabella dei risultati dovrebbe combinare nuovamente le righe.Ciò presuppone che InStage1 e InStage2 non siano mai entrambi "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
Sono riuscito a farlo funzionare con una variazione della risposta di BCS.Tuttavia non mi permetteva di usare una variabile di tabella, quindi ho dovuto creare una tabella temporanea.
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