it-swarm.com.de

Verschieben von Zeilen von einer Tabelle in eine andere

Ich verschiebe Datensätze als Teil des Archivierungsprozesses von einer Datenbank in eine andere. Ich möchte die Zeilen in die Zieltabelle kopieren und dann dieselben Zeilen aus der Quelltabelle löschen.

Meine Frage ist, wie man am effizientesten prüft, ob die erste Einfügung erfolgreich war, bevor die Zeilen gelöscht werden.

Meine Idee ist dies, aber ich denke, es gibt einen besseren Weg:

@num_records=select count(ID) from Source_Table where (criteria for eligible rows)

insert * into Destination_Table where (criteria for eligible rows)

if ((select count(ID) from Destination_Table where (criteria) )[email protected])

delete * from Source_Table where (criteria)

Ist es besser/möglich, es mit der RAISERROR-Funktion zu kombinieren? Vielen Dank!

9
Dina

Ich würde TRY/CATCH Syntax zusammen mit expliziten Transaktionen empfehlen. Ich gehe für diese Lösung davon aus, dass der Grund für den Einfügefehler eine Art abfangbarer SQL-Fehler ist (z. B. eine Schlüsselverletzung, ein Fehlanpassungs-/Konvertierungsfehler des Datentyps usw.). Die Struktur würde so aussehen:

BEGIN TRAN

BEGIN TRY
  INSERT INTO foo(col_a,col_b,col_c,recdate)
  SELECT col_a,col_b,col_c,recdate
  FROM bar
  WHERE recdate BETWEEN @startdate AND @enddate

  DELETE FROM bar
  WHERE recdate BETWEEN @startdate AND @enddate

  COMMIT TRAN
END TRY
BEGIN CATCH
  ROLLBACK TRAN
END CATCH

So wie diese Struktur funktioniert: Wenn im INSERT oder im DELETE ein Fehler auftritt, wird die gesamte Aktion zurückgesetzt. Dies garantiert, dass die gesamte Aktion erfolgreich sein muss, um abgeschlossen zu werden. Wenn Sie der Meinung sind, dass dies notwendig ist, können Sie es mit [~ # ~] throw [~ # ~] für 2012 oder [~ # ~] Raiserror [~ # ~] im Jahr 2008 und früher, um zusätzliche Logik hinzuzufügen und einen Rollback zu erzwingen, wenn diese Logik nicht erfüllt wurde.

Eine andere Möglichkeit ist, sich SET XACT_ABORT ON anzusehen, obwohl ich der Meinung bin, dass die TRY/CATCH-Syntax Ihnen mehr Granularität bietet.

13
Mike Fal

Wenn Ihre Archivtabelle nicht .

  • Haben darauf definierte Trigger aktiviert.
  • Nehmen Sie an beiden Seiten einer FOREIGN KEY-Einschränkung teil.
  • CHECK-Einschränkungen oder aktivierte Regeln haben.

Sie können dies auch in einem Status tun.

DELETE FROM source_table
OUTPUT deleted.Foo,
       deleted.Bar,
       SYSUTCDATETIME()
INTO archive_table(Foo, Bar, archived)
WHERE  Foo = 1; 

Dies wird als Einheit entweder erfolgreich sein oder fehlschlagen und vermeidet auch mögliche Race-Bedingungen, da Zeilen zwischen INSERT zum Archiv und DELETE hinzugefügt werden (obwohl Ihre WHERE -Klausel möglicherweise gut ist machen dies sowieso extrem unwahrscheinlich).

19
Martin Smith

Versuche dies:

INSERT dbo.newtable(
      name,
      department,
      Salary
) SELECT 
            name,
            FirstName,
            Lastname
      FROM    (
           DELETE dbo.oldtable
           OUTPUT
                   DELETED.name,
                   DELETED.department,
                   DELETED.Salary
           WHERE ID  IN ( 1001, 1003, 1005 )
      ) AS RowsToMove;

SELECT * FROM dbo.newtable;
SELECT * FROM dbo.oldtable;
1
Nadeem

Die Art und Weise, wie ich über die Archivierung nachgedacht habe (was sicher auch nicht perfekt ist), besteht darin, der neuen Archivtabelle eine Bitspalte wie "Archiviert" hinzuzufügen, die nach erfolgreicher Übertragung eines Datensatzes den Wert 1 hätte. Sobald Sie alle Datensätze übertragen haben, können Sie einen Löschvorgang ausführen und gleichzeitig nach dem Feldwert 'Archiviert' von '1' suchen, d. H. True aus der archivierten Tabelle.

Und ich stimme Mike bei der Verwendung von Try/Catch zu.

1
avakharia