UPSERT (UPDATE + INSERT) 是資料同步常見需求。本文提供標準預存程序實作,依主鍵判斷:資料完全相同 → 回傳 0;主鍵相同但資料不同 → 更新回傳 2;主鍵不存在 → 插入回傳 1。附完整建立與呼叫腳本。
| 狀況 | 動作 | 回傳值 |
|---|---|---|
| 主鍵存在且所有欄位值相同 | 無操作 | 0 |
| 主鍵存在但至少一欄位值不同 | UPDATE | 2 |
| 主鍵不存在 | INSERT | 1 |
CREATE PROCEDURE Insert_Update
@Id VARCHAR(20),
@Name VARCHAR(20),
@Telephone VARCHAR(20),
@Address VARCHAR(20),
@Job VARCHAR(20),
@returnValue INT OUTPUT
AS
BEGIN
DECLARE @tmpName VARCHAR(20), @tmpTelephone VARCHAR(20),
@tmpAddress VARCHAR(20), @tmpJob VARCHAR(20);
IF EXISTS (SELECT * FROM dbo.DemoData WHERE id = @Id)
BEGIN
-- 讀取現有值
SELECT @tmpName = Name, @tmpTelephone = Telephone,
@tmpAddress = Address, @tmpJob = Job
FROM dbo.DemoData WHERE id = @Id;
-- 比較所有欄位
IF (@tmpName = @Name AND @tmpTelephone = @Telephone
AND @tmpAddress = @Address AND @tmpJob = @Job)
BEGIN
SET @returnValue = 0; -- 完全相同,無操作
END
ELSE
BEGIN
UPDATE dbo.DemoData
SET Name = @Name, Telephone = @Telephone,
Address = @Address, Job = @Job
WHERE id = @Id;
SET @returnValue = 2; -- 更新
END
END
ELSE
BEGIN
INSERT INTO dbo.DemoData (Id, Name, Telephone, Address, Job)
VALUES (@Id, @Name, @Telephone, @Address, @Job);
SET @returnValue = 1; -- 插入
END
END
GO
DECLARE @returnValue INT;
EXEC Insert_Update '15', 'hugh15', '3823345', '長安街', '副部長', @returnValue OUTPUT;
SELECT @returnValue AS ResultCode;
-- 0 = 已存在相同資料
-- 1 = 插入成功
-- 2 = 更新成功
MERGE INTO dbo.DemoData AS target
USING (VALUES (@Id, @Name, @Telephone, @Address, @Job))
AS source (Id, Name, Telephone, Address, Job)
ON target.Id = source.Id
WHEN MATCHED AND (target.Name <> source.Name OR ...)
THEN UPDATE SET ...
WHEN NOT MATCHED
THEN INSERT ...;
OUTPUT $action, inserted.*, deleted.* 記錄實際執行動作。Id 為主鍵/唯一索引,確保查找為 Seek。UPDLOCK, HOLDLOCK 提示或可序列化隔離等級。此 UPSERT 模式清晰、可擴展,配合 MERGE 進一步簡化邏輯並增強並發安全性,是資料同步作業的標準範本。