J'ai une table avec des données nommées energydata
il n'a que trois colonnes
(webmeterID, DateTime, kWh)
J'ai un nouvel ensemble de données mises à jour dans une table temp_energydata
.
La DateTime
et la webmeterID
restent les mêmes. Mais les valeurs kWh
doivent être mises à jour à partir de la table temp_energydata
.
Comment est-ce que j'écris le T-SQL pour ceci correctement?
En supposant que vous souhaitiez obtenir une instruction SQL Server MERGE
:
MERGE INTO dbo.energydata WITH (HOLDLOCK) AS target
USING dbo.temp_energydata AS source
ON target.webmeterID = source.webmeterID
AND target.DateTime = source.DateTime
WHEN MATCHED THEN
UPDATE SET target.kWh = source.kWh
WHEN NOT MATCHED BY TARGET THEN
INSERT (webmeterID, DateTime, kWh)
VALUES (source.webmeterID, source.DateTime, source.kWh);
Si vous souhaitez également supprimer des enregistrements de la cible qui ne figurent pas dans la source:
MERGE INTO dbo.energydata WITH (HOLDLOCK) AS target
USING dbo.temp_energydata AS source
ON target.webmeterID = source.webmeterID
AND target.DateTime = source.DateTime
WHEN MATCHED THEN
UPDATE SET target.kWh = source.kWh
WHEN NOT MATCHED BY TARGET THEN
INSERT (webmeterID, DateTime, kWh)
VALUES (source.webmeterID, source.DateTime, source.kWh)
WHEN NOT MATCHED BY SOURCE THEN
DELETE;
Parce que cela est devenu un peu plus populaire, je pense que je devrais développer un peu cette réponse avec quelques mises en garde à prendre en compte.
Premièrement, plusieurs blogs signalent des problèmes de simultanéité avec l'instruction MERGE
dans des versions antérieures de SQL Server. Je ne sais pas si cette question a déjà été abordée dans les éditions ultérieures. Dans les deux cas, vous pouvez en grande partie contourner le problème en spécifiant l'indicateur de verrouillage HOLDLOCK
ou SERIALIZABLE
:
MERGE INTO dbo.energydata WITH (HOLDLOCK) AS target
[...]
Vous pouvez également accomplir la même chose avec des niveaux d'isolation de transaction plus restrictifs.
Il existe plusieurs autres problèmes connus avec MERGE
. (Notez que depuis que Microsoft a nuancé Connect et n'a pas lié les problèmes de l'ancien système aux problèmes du nouveau système, ces problèmes plus anciens sont difficiles à dépister. Merci, Microsoft!) D'après ce que je peux dire, la plupart d'entre eux ne sont pas courants. problèmes ou peuvent être résolus avec les mêmes astuces de verrouillage que ci-dessus, mais je ne les ai pas testés.
Dans l’état actuel des choses, même si j’ai jamais eu de problèmes avec l’instruction MERGE
, j’utilise toujours l’indicateur WITH (HOLDLOCK)
à présent, et je préfère utiliser l’énoncé uniquement dans les cas les plus simples.
J'ai souvent utilisé Bacon Bits excellente réponse car je ne peux tout simplement pas mémoriser la syntaxe.
Mais j’ajoute généralement un CTE comme complément pour rendre la partie DELETE plus utile car très souvent, vous souhaiterez appliquer la fusion uniquement à une partie de la table cible.
WITH target as (
SELECT * FROM dbo.energydate WHERE DateTime > GETDATE()
)
MERGE INTO target WITH (HOLDLOCK)
USING dbo.temp_energydata AS source
ON target.webmeterID = source.webmeterID
AND target.DateTime = source.DateTime
WHEN MATCHED THEN
UPDATE SET target.kWh = source.kWh
WHEN NOT MATCHED BY TARGET THEN
INSERT (webmeterID, DateTime, kWh)
VALUES (source.webmeterID, source.DateTime, source.kWh)
WHEN NOT MATCHED BY SOURCE THEN
DELETE
Si vous avez simplement besoin de mettre à jour vos enregistrements dans energydata
en vous basant sur les données de temp_energydata
, en supposant que temp_enerydata
ne contient aucun nouvel enregistrement, essayez ceci:
UPDATE e SET e.kWh = t.kWh
FROM energydata e INNER JOIN
temp_energydata t ON e.webmeterID = t.webmeterID AND
e.DateTime = t.DateTime
Ici fonctionne sqlfiddle
Mais si temp_energydata
contient de nouveaux enregistrements et que vous devez l'insérer dans energydata
, de préférence avec une déclaration, vous devez absolument choisir la réponse donnée par Bacon Bits.
UPDATE ed
SET ed.kWh = ted.kWh
FROM energydata ed
INNER JOIN temp_energydata ted ON ted.webmeterID = ed.webmeterID
Update energydata set energydata.kWh = temp.kWh
where energydata.webmeterID = (select webmeterID from temp_energydata as temp)