J'essaie de trouver un équivalent de la requête MySql suivante dans Sql Server (2012)?
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);
Quelqu'un peut-il aider?
PS. J'ai lu que la requête MERGE
a une fonction similaire, mais je trouve la syntaxe de celle-ci très différente.
Vous recherchez essentiellement un modèle d'insertion ou de mise à jour parfois appelé Upsert.
Je recommande ceci: Insérer ou mettre à jour le modèle pour Sql Server - Sam Saffron
Pour une procédure qui traitera de lignes uniques, ces transactions fonctionneraient bien:
Première solution de Sam Saffron (adaptée à ce schéma):
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
La deuxième solution de Sam Saffron (adaptée à ce schéma):
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
Même avec une utilisation créative de IGNORE_DUP_KEY
, vous seriez toujours obligé d'utiliser un bloc d'insertion/mise à jour ou une instruction de fusion.
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'
);
La réponse de fusion fournie par Spock devrait faire ce que vous voulez.
La fusion n'est pas nécessairement recommandée. Je l'utilise, mais je ne l'admettrais jamais à @AaronBertrand.
Essayez ceci ... J'ai ajouté des commentaires pour essayer d'expliquer ce qui se passe où dans une instruction SQL Merge. Source: MSDN: instruction de fusion
L'instruction de fusion est différente de l'instruction ON DUPLICATE KEY UPDATE en ce que vous pouvez lui indiquer les colonnes à utiliser pour la fusion.
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)
J'espère que cela pourra aider
La procédure stockée sauvera la journée.
Ici, je suppose que COL_A et COL_B sont des colonnes uniques et sont de type INT NB! Ne pas avoir d'instance ATM de serveur SQL, donc ne peut pas garantir l'exactitude de la syntaxe. MISE À JOUR! Voici un lien vers 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
Appelez ensuite cette procédure avec les valeurs nécessaires au lieu de l'instruction Update
exec updateDuplicate 1, 1, 1, 2
GO
SELECT * from mytable
GO
Vous pouvez simuler un comportement presque identique en utilisant un 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;
Comment ça marche
LEFT OUTER JOIN
sur la ou les colonnes clés COL_D
qui détectent les critères de duplication.INSERT
, en insérant les lignes qui ne sont pas déjà dans la table (à cause de la INSTEAD OF
, nous avons supprimé la responsabilité de l'insertion du moteur et devons le faire nous-mêmes).Points saillants
INSTEAD OF
le déclencheur est en place.COL_D
dans ce cas, mais il pourrait s'agir d'une clé composite. (Clé mais ne peut pas être IDENTITY
pour des raisons évidentes, car le client n'insérera pas d'identité)[~ # ~] nb [~ # ~]
INSTEAD OF
déclencheurs - car cela peut provoquer des changements surprenants dans le comportement observable de Sql Server, comme celui-ci - même bien intentionnés INSTEAD OF
les déclencheurs peuvent entraîner des heures d'efforts inutiles et de la frustration pour les développeurs et les administrateurs de base de données qui ne sont pas conscients de leur présence sur votre table.Il n'y a pas DUPLICATE KEY UPDATE
équivalent dans le serveur sql, mais vous pouvez utiliser fusionné et quand il est mis en correspondance avec le serveur sql pour y arriver, jetez un œil ici: plusieurs opérations utilisant la fusion