738 Stimmen

Lösungen für INSERT OR UPDATE auf SQL Server

Nehmen wir eine Tabellenstruktur von MyTable(KEY, datafield1, datafield2...) .

Häufig möchte ich entweder einen vorhandenen Datensatz aktualisieren oder einen neuen Datensatz einfügen, wenn dieser noch nicht existiert.

Im Wesentlichen:

IF (key exists)
  run update command
ELSE
  run insert command

Wie kann man das am besten schreiben?

53 Stimmen

Für alle, die diese Frage zum ersten Mal stellen - bitte lesen Sie unbedingt alle Antworten und Kommentare. Das Alter kann manchmal zu irreführenden Informationen führen...

1 Stimmen

Erwägen Sie die Verwendung des EXCEPT-Operators, der in SQL Server 2005 eingeführt wurde.

38voto

Eric Weilnau Punkte 5092

Wenn Sie mehr als einen Datensatz auf einmal UPSERT möchten, können Sie die ANSI SQL:2003 DML-Anweisung MERGE verwenden.

MERGE INTO table_name WITH (HOLDLOCK) USING table_name ON (condition)
WHEN MATCHED THEN UPDATE SET column1 = value1 [, column2 = value2 ...]
WHEN NOT MATCHED THEN INSERT (column1 [, column2 ...]) VALUES (value1 [, value2 ...])

Überprüfen Sie Nachahmung der MERGE-Anweisung in SQL Server 2005 .

1 Stimmen

In Oracle ist die Ausgabe einer MERGE-Anweisung I denken sperrt den Tisch. Geschieht dasselbe in SQL*Server?

14 Stimmen

MERGE ist anfällig für Race Conditions (siehe weblogs.sqlteam.com/dang/archive/2009/01/31/ ), es sei denn, Sie lassen es bestimmte Schlösser halten. Werfen Sie auch einen Blick auf die Leistung von MERGE im SQL Profiler ... ich finde, dass es typischerweise langsamer ist und mehr Lesevorgänge erzeugt als alternative Lösungen.

0 Stimmen

@EBarr - Danke für den Link zu den Schlössern. Ich habe meine Antwort aktualisiert, um den Hinweis auf die Sperren aufzunehmen.

11voto

user243131 Punkte 129

Obwohl es ziemlich spät ist, dies zu kommentieren, möchte ich ein vollständigeres Beispiel mit MERGE hinzufügen.

Solche Insert+Update-Anweisungen werden in der Regel als "Upsert"-Anweisungen bezeichnet und können mit MERGE in SQL Server implementiert werden.

Ein sehr gutes Beispiel wird hier gegeben: http://weblogs.sqlteam.com/dang/archive/2009/01/31/UPSERT-Race-Condition-With-MERGE.aspx

Die obigen Ausführungen erklären auch Sperren und Gleichzeitigkeitsszenarien.

Ich werde das Gleiche als Referenz zitieren:

ALTER PROCEDURE dbo.Merge_Foo2
      @ID int
AS

SET NOCOUNT, XACT_ABORT ON;

MERGE dbo.Foo2 WITH (HOLDLOCK) AS f
USING (SELECT @ID AS ID) AS new_foo
      ON f.ID = new_foo.ID
WHEN MATCHED THEN
    UPDATE
            SET f.UpdateSpid = @@SPID,
            UpdateTime = SYSDATETIME()
WHEN NOT MATCHED THEN
    INSERT
      (
            ID,
            InsertSpid,
            InsertTime
      )
    VALUES
      (
            new_foo.ID,
            @@SPID,
            SYSDATETIME()
      );

RETURN @@ERROR;

1 Stimmen

Es gibt noch andere Dinge, die bei MERGE zu beachten sind: mssqltips.com/sqlservertip/3074/

7voto

Denver Punkte 79
/*
CREATE TABLE ApplicationsDesSocietes (
   id                   INT IDENTITY(0,1)    NOT NULL,
   applicationId        INT                  NOT NULL,
   societeId            INT                  NOT NULL,
   suppression          BIT                  NULL,
   CONSTRAINT PK_APPLICATIONSDESSOCIETES PRIMARY KEY (id)
)
GO
--*/

DECLARE @applicationId INT = 81, @societeId INT = 43, @suppression BIT = 0

MERGE dbo.ApplicationsDesSocietes WITH (HOLDLOCK) AS target
--set the SOURCE table one row
USING (VALUES (@applicationId, @societeId, @suppression))
    AS source (applicationId, societeId, suppression)
    --here goes the ON join condition
    ON target.applicationId = source.applicationId and target.societeId = source.societeId
WHEN MATCHED THEN
    UPDATE
    --place your list of SET here
    SET target.suppression = source.suppression
WHEN NOT MATCHED THEN
    --insert a new line with the SOURCE table one row
    INSERT (applicationId, societeId, suppression)
    VALUES (source.applicationId, source.societeId, source.suppression);
GO

Ersetzen Sie Tabellen- und Feldnamen durch die von Ihnen benötigten. Kümmern Sie sich um die mit ON Zustand. Legen Sie dann den entsprechenden Wert (und Typ) für die Variablen in der DECLARE-Zeile fest.

Zum Wohl.

6voto

Daniel Acosta Punkte 69

Sie können verwenden MERGE Anweisung, Diese Anweisung wird verwendet, um Daten einzufügen, wenn sie nicht vorhanden sind, oder zu aktualisieren, wenn sie vorhanden sind.

MERGE INTO Employee AS e
using EmployeeUpdate AS eu
ON e.EmployeeID = eu.EmployeeID`

0 Stimmen

@RamenChef Ich verstehe das nicht. Wo sind die WHEN MATCHED-Klauseln?

0 Stimmen

@likejudo Ich habe das nicht geschrieben, sondern nur überarbeitet. Fragen Sie den Benutzer, der den Beitrag geschrieben hat.

6voto

Saleh Najar Punkte 61

Das hängt von der Art der Nutzung ab. Man muss das Gesamtbild der Nutzung betrachten, ohne sich in den Details zu verlieren. Wenn das Nutzungsmuster beispielsweise zu 99 % aus Aktualisierungen besteht, nachdem der Datensatz erstellt wurde, ist "UPSERT" die beste Lösung.

Nach der ersten Einfügung (Treffer) werden alle Aktualisierungen mit einer einzigen Anweisung erfolgen, ohne Wenn und Aber. Die "where"-Bedingung für die Einfügung ist notwendig, da sonst Duplikate eingefügt werden und Sie sich nicht mit Sperren befassen wollen.

UPDATE <tableName> SET <field>=@field WHERE key=@key;

IF @@ROWCOUNT = 0
BEGIN
   INSERT INTO <tableName> (field)
   SELECT @field
   WHERE NOT EXISTS (select * from tableName where key = @key);
END

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X