我试图在Sql Server(2012)中找到以下MySql查询的等价物?
INSERT INTO mytable (COL_A, COL_B, COL_C, COL_D)
VALUES ( 'VAL_A','VAL_B', 'VAL_C', 'VAL_D')
ON DUPLICATE KEY UPDATE COL_D= VALUES(COL_D);
有人可以帮忙吗?
PS。我已经读过MERGE
查询具有类似的功能,但我发现它的语法非常不同。
答案 0 :(得分:18)
您基本上在寻找插入或更新模式,有时也称为 Upsert。
我建议:Insert or Update pattern for Sql Server - Sam Saffron
对于将处理单行的过程,这些事务都可以正常工作:
begin tran
if exists (
select *
from mytable with (updlock,serializable)
where col_a = @val_a
and col_b = @val_b
and col_c = @val_c
)
begin
update mytable
set col_d = @val_d
where col_a = @val_a
and col_b = @val_b
and col_c = @val_c;
end
else
begin
insert into mytable (col_a, col_b, col_c, col_d)
values (@val_a, @val_b, @val_c, @val_d);
end
commit tran
begin tran
update mytable with (serializable)
set col_d = @val_d
where col_a = @val_a
and col_b = @val_b
and col_c = @val_c;
if @@rowcount = 0
begin
insert into mytable (col_a, col_b, col_c, col_d)
values (@val_a, @val_b, @val_c, @val_d);
end
commit tran
即使有创意使用 IGNORE_DUP_KEY
,您仍然不得不使用插入/更新块或合并声明。
update mytable
set col_d = 'val_d'
where col_a = 'val_a'
and col_b = 'val_b'
and col_c = 'val_c';
insert into mytable (col_a, col_b, col_c, col_d)
select 'val_a','val_b', 'val_c', 'val_d'
where not exists (select *
from mytable with (serializable)
where col_a = 'val_a'
and col_b = 'val_b'
and col_c = 'val_c'
);
The Merge answer provided by Spock应该做你想做的事。
不一定建议使用合并。我用它,但我永远不会承认@AaronBertrand。
答案 1 :(得分:9)
试试这个...... 我添加了注释以尝试解释在SQL Merge语句中发生的情况。 资料来源:MSDN : Merge Statement
Merge语句与ON DUPLICATE KEY UPDATE语句的不同之处在于,您可以告诉它使用哪些列进行合并。
CREATE TABLE #mytable(COL_A VARCHAR(10), COL_B VARCHAR(10), COL_C VARCHAR(10), COL_D VARCHAR(10))
INSERT INTO #mytable VALUES('1','0.1', '0.2', '0.3'); --<These are the values we'll be updating
SELECT * FROM #mytable --< Starting values (1 row)
MERGE #mytable AS target --< This is the target we want to merge into
USING ( --< This is the source of your merge. Can me any select statement
SELECT '1' AS VAL_A,'1.1' AS VAL_B, '1.2' AS VAL_C, '1.3' AS VAL_D --<These are the values we'll use for the update. (Assuming column COL_A = '1' = Primary Key)
UNION
SELECT '2' AS VAL_A,'2.1' AS VAL_B, '2.2' AS VAL_C, '2.3' AS VAL_D) --<These values will be inserted (cause no COL_A = '2' exists)
AS source (VAL_A, VAL_B, VAL_C, VAL_D) --< Column Names of our virtual "Source" table
ON (target.COL_A = source.VAL_A) --< This is what we'll use to find a match "JOIN source on Target" using the Primary Key
WHEN MATCHED THEN --< This is what we'll do WHEN we find a match, in your example, UPDATE COL_D = VALUES(COL_D);
UPDATE SET
target.COL_B = source.VAL_B,
target.COL_C = source.VAL_C,
target.COL_D = source.VAL_D
WHEN NOT MATCHED THEN --< This is what we'll do when we didn't find a match
INSERT (COL_A, COL_B, COL_C, COL_D)
VALUES (source.VAL_A, source.VAL_B, source.VAL_C, source.VAL_D)
--OUTPUT deleted.*, $action, inserted.* --< Uncomment this if you want a summary of what was inserted on updated.
--INTO #Output --< Uncomment this if you want the results to be stored in another table. NOTE* The table must exists
;
SELECT * FROM #mytable --< Ending values (2 row, 1 new, 1 updated)
希望有所帮助
答案 2 :(得分:2)
存储过程将节省一天。
这里我假设COL_A和COL_B是唯一的列,是INT的类型 NB!没有sql-server实例ATM因此无法保证语法的正确性。 UPDATE!这是SQLFIDDLE
的链接 CREATE TABLE mytable
(
COL_A int UNIQUE,
COL_B int UNIQUE,
COL_C int,
COL_D int,
)
GO
INSERT INTO mytable (COL_A, COL_B, COL_C, COL_D)
VALUES (1,1,1,1),
(2,2,2,2),
(3,3,3,3),
(4,4,4,4);
GO
CREATE PROCEDURE updateDuplicate(@COL_A INT, @COL_B INT, @COL_C INT, @COL_D INT)
AS
BEGIN
DECLARE @ret INT
SELECT @ret = COUNT(*)
FROM mytable p
WHERE p.COL_A = @COL_A
AND p.COL_B = @COL_B
IF (@ret = 0)
INSERT INTO mytable (COL_A, COL_B, COL_C, COL_D)
VALUES ( @COL_A, @COL_B, @COL_C, @COL_D)
IF (@ret > 0)
UPDATE mytable SET COL_D = @COL_D WHERE col_A = @COL_A AND COL_B = @COL_B
END;
GO
然后使用所需的值而不是Update语句
调用此过程exec updateDuplicate 1, 1, 1, 2
GO
SELECT * from mytable
GO
答案 3 :(得分:2)
您可以使用INSTEAD OF TRIGGER
:
CREATE TRIGGER tMyTable ON MyTable
INSTEAD OF INSERT
AS
BEGIN
SET NOCOUNT ON;
SELECT i.COL_A, i.COL_B, i.COL_C, i.COL_D,
CASE WHEN mt.COL_D IS NULL THEN 0 ELSE 1 END AS KeyExists
INTO #tmpMyTable
FROM INSERTED i
LEFT JOIN MyTable mt
ON i.COL_D = mt.COL_D;
INSERT INTO MyTable(COL_A, COL_B, COL_C, COL_D)
SELECT COL_A, COL_B, COL_C, COL_D
FROM #tmpMyTable
WHERE KeyExists = 0;
UPDATE mt
SET mt.COL_A = t.COL_A, mt.COL_B = t.COL_B, mt.COL_C = t.COL_C
FROM MyTable mt
INNER JOIN #tmpMyTable t
ON mt.COL_D = t.COL_D AND t.KeyExists = 1;
END;
工作原理
LEFT OUTER JOIN
注意其中哪些ARE已经在基础表中{ {1}}检测重复标准。COL_D
语句的实际工作,通过插入表中尚未存在的那些行(由于INSERT
,我们已经删除了插入的责任引擎,需要自己做。)显着点
INSTEAD OF
触发器已就位。INSTEAD OF
,但它可能是一个复合键。 (密钥但由于明显的原因不能COL_D
,因为客户端不会插入标识)NB
IDENTITY
触发更多 - 因为这会导致Sql Server的可观察行为发生意外变化,例如: - 即使是好的INSTEAD OF
触发器也会导致为开发人员和没有意识到他们出现在桌面上的DBA而浪费了数小时的努力和挫折。答案 4 :(得分:0)
在sql server中没有DUPLICATE KEY UPDATE
等价物,但是你可以使用merged和sql server匹配来完成这个,看看这里:
multiple operations using merge