Ich versuche, eine Tabelle mit einem Array von Werten zu aktualisieren. Jedes Element im Array enthält Informationen, die mit einer Zeile in einer Tabelle in der SQL Server-Datenbank übereinstimmen. Wenn die Zeile bereits in der Tabelle vorhanden ist, aktualisieren wir diese Zeile mit den Informationen im angegebenen Array. Andernfalls fügen wir eine neue Zeile in die Tabelle ein. Ich habe im Grunde Upsert beschrieben.
Jetzt versuche ich dies in einer gespeicherten Prozedur zu erreichen, die einen XML-Parameter verwendet. Der Grund, warum ich XML und keine tabellenwertigen Parameter verwende, ist, dass ich in letzterem Fall einen benutzerdefinierten Typ in SQL erstellen und diesen Typ der gespeicherten Prozedur zuordnen muss. Wenn ich jemals etwas an meiner gespeicherten Prozedur oder meinem Datenbankschema ändern würde, müsste ich sowohl die gespeicherte Prozedur als auch den benutzerdefinierten Typ wiederholen. Ich möchte diese Situation vermeiden. Außerdem ist die Überlegenheit, die TVP gegenüber XML hat, für meine Situation nicht nützlich, da meine Datenarraygröße niemals 1000 überschreitet. Dies bedeutet, dass ich die hier vorgeschlagene Lösung nicht verwenden kann: So fügen Sie mehrere Datensätze mit XML in SQL Server 2008 ein
Eine ähnliche Diskussion hier ( UPSERT - Gibt es eine bessere Alternative zu MERGE oder @@ rowcount? ) Unterscheidet sich von dem, was ich frage, weil ich versuche, mehrere Zeilen in eine Tabelle einzufügen .
Ich hatte gehofft, dass ich einfach die folgenden Abfragen verwenden würde, um die Werte aus der XML zu erhöhen. Aber das wird nicht funktionieren. Dieser Ansatz soll nur funktionieren, wenn die Eingabe eine einzelne Zeile ist.
begin tran
update table with (serializable) set select * from xml_param
where key = @key
if @@rowcount = 0
begin
insert table (key, ...) values (@key,..)
end
commit tran
Die nächste Alternative besteht darin, ein erschöpfendes IF EXISTS oder eine seiner Variationen der folgenden Form zu verwenden. Ich lehne dies jedoch aus Gründen der suboptimalen Effizienz ab:
IF (SELECT COUNT ... ) > 0
UPDATE
ELSE
INSERT
Die nächste Option war die Verwendung der Merge-Anweisung wie hier beschrieben: http://www.databasejournal.com/features/mssql/using-the-merge-statement-to-perform-an-upsert.html . Aber dann habe ich hier über Probleme mit der Zusammenführungsabfrage gelesen: http://www.mssqltips.com/sqlservertip/3074/use-caution-with-sql-servers-merge-statement/ . Aus diesem Grund versuche ich, Merge zu vermeiden.
Meine Frage lautet nun: Gibt es eine andere Option oder einen besseren Weg, um mithilfe von XML-Parametern in gespeicherten SQL Server 2008-Prozeduren mehrere Upsert zu erzielen?
Bitte beachten Sie, dass die Daten im XML-Parameter möglicherweise einige Datensätze enthalten, die nicht UPSERTed werden sollten, da sie älter als der aktuelle Datensatz sind. ModifiedDate
Sowohl in der XML- als auch in der Zieltabelle gibt es ein Feld, das verglichen werden muss, um festzustellen, ob der Datensatz aktualisiert oder verworfen werden soll.
MERGE
, auf die Bertrand hinweist, sind meistens Randfälle und Ineffizienzen, keine Stopper - MS hätte es nicht veröffentlicht, wenn es ein echtes Minenfeld gewesen wäre. Sind Sie sicher, dass die Windungen, die Sie vermeiden MERGE
möchten, nicht mehr potenzielle Fehler verursachen als sie speichern?
MERGE
. Die Schritte INSERT und UPDATE von MERGE werden weiterhin separat verarbeitet. Der Hauptunterschied in meinem Ansatz ist die Tabellenvariable, die die aktualisierten Datensatz-IDs enthält, und die DELETE-Abfrage, die diese Tabellenvariable verwendet, um diese Datensätze aus der temporären Tabelle der eingehenden Daten zu entfernen. Und ich nehme an, die QUELLE könnte direkt von @ XMLparam.nodes () stammen, anstatt in eine temporäre Tabelle zu kopieren, aber das ist nicht viel zusätzliches Zeug, um sich keine Sorgen machen zu müssen, jemals in einem dieser Randfälle zu sein; - ).