테이블에 Upsert를 수행하려면 어떻게 해야 합니까?
-
09-06-2019 - |
문제
할당된 사람과 현재 단계와 같은 데이터가 포함된 작업 목록이 포함된 뷰가 있습니다.각 단계에서 각 사람이 가지고 있는 작업 수를 반환하는 저장 프로시저를 작성해야 합니다.
지금까지 나는 이것을 가지고 있습니다 (단순화):
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를 사용하고 있습니다.
편집하다:@이씨: 불행히도 InStage1 = 1은 단순화되었습니다.이는 DateStarted가 NULL이 아니고 DateFinished가 NULL인 WHERE DateStarted와 비슷합니다.
편집하다:@BCS: 나는 모든 직원을 먼저 삽입하는 아이디어를 좋아하므로 매번 업데이트만 하면 됩니다.하지만 저는 UPDATE 문을 올바르게 작성하는 데 어려움을 겪고 있습니다.
해결책
IIRC에는 행이 존재하는 경우 업데이트할 수 있는 일종의 "On Duplicate"(이름이 잘못되었을 수 있음) 구문이 있습니다(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)
다른 팁
사실 지금보다 훨씬 더 열심히 하고 계신 것 같아요.이 코드가 당신이 하려는 일에 작동하지 않나요?
SELECT StaffName, SUM(InStage1) AS 'JobsAtStage1', SUM(InStage2) AS 'JobsAtStage2'
FROM ViewJob
GROUP BY StaffName
존재 여부를 확인하고 적절한 명령을 사용할 수 있습니다.나는 이것이 실제로 뒤에서 커서를 사용한다고 생각하지만 얻을 수 있는 최고는 다음과 같습니다.
IF (EXISTS (SELECT * FROM MyTable WHERE StaffName = @StaffName))
begin
UPDATE MyTable SET ... WHERE StaffName = @StaffName
end
else
begin
INSERT MyTable ...
end
SQL2008에는 멋진 새로운 MERGE 기능이 있지만 2005에는 없습니다.
실제 "upsert" 유형의 쿼리를 얻으려면 존재하는 경우를 사용해야 합니다...이는 불행하게도 커서를 사용하는 것을 의미합니다.
그러나 두 개의 쿼리를 실행할 수 있습니다. 하나는 기존 행이 있는 업데이트를 수행한 다음 나중에 새 행을 삽입하는 것입니다.소수의 행만 처리하는 경우가 아니라면 이 집합 기반 접근 방식이 더 바람직하다고 생각합니다.
결과 테이블의 다음 쿼리는 행을 다시 결합해야 합니다.이는 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
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