Erstellen einen SQL Server-Trigger, um den Übergang von einem natürlichen Schlüssel zu einem Ersatzschlüssel

StackOverflow https://stackoverflow.com/questions/3938287

Frage

Backstory

Bei der Arbeit, wo wir planen eine Naturschlüsselspalte in einem unserer primären Tabellen auf ironischen. Das Projekt besteht aus mehr als 100 Anwendungen, die auf diesen Tisch / Spalte; 400+ Verfahren gespeichert, die diese Spalte direkt referenzieren; und eine Vielzahl von gemeinsamen Tabellen zwischen diesen Anwendungen, die auch in dieser Spalte verweisen.

The Big Bang und Start aus Scratch Methoden des Bildes aus. Wir werden diesen Spalt eine Anwendung zu einem Zeitpunkt, verbitten, bescheinigen die Änderungen, und gehen Sie zum nächsten ... und wir haben eine lange Torwand bekommen diese Anstrengung praktisch zu machen.

Das Problem, das ich habe, ist, dass viele dieser Anwendungen gespeicherte Prozeduren und Tabellen geteilt haben. Wenn ich vollständig alle Anwendungs ??A Tische / gespeicherte Prozeduren Anwendung B und C zu konvertieren bis konvertierte gebrochen werden. Diese können wiederum brechen Anwendungen D, E, F ... usw. Ich habe bereits eine Strategie für-Code-Klassen implementiert und Stored Procedures, den Teil I bin stecken auf dem transitioning Zustand der Datenbank ist.

Hier ist ein Grund Beispiel dafür, was wir haben:

Users
---------------------------
Code          varchar(32) natural key

Access
---------------------------
UserCode      varchar(32) foreign key
AccessLevel   int

Und wir streben jetzt nur für Übergangszustand wie folgt aus:

Users
---------------------------
Code          varchar(32) 
Id            int         surrogate key

Access
---------------------------
UserCode      varchar(32)   
UserID        int         foreign key      
AccessLevel   int

Die Idee während der Übergangsphase nicht-migrierten Anwendungen sein und gespeicherte Prozeduren noch in der Lage sein, alle geeigneten Daten zuzugreifen und neue beginnen, um die richtigen Spalten drängen - Sobald die Migration für alle gespeicherten Prozeduren abgeschlossen ist und Anwendungen können wir endlich die zusätzlichen Spalten fallen.

Ich wollte SQL Server Trigger automatisch abfangen jeden neuen Insert / Update und Einschränkungen in etwa wie folgt auf jedem der betroffenen Tabellen verwenden:

CREATE TRIGGER tr_Access_Sync
ON Access
INSTEAD OF INSERT(, UPDATE)
AS
BEGIN
  DIM @code as Varchar(32)
  DIM @id as int

  SET @code = (SELECT inserted.code FROM inserted)
  SET @id = (SELECT inserted.code FROM inserted)

  -- This is a migrated application; find the appropriate legacy key
  IF @code IS NULL AND @id IS NOT NULL
     SELECT Code FROM Users WHERE Users.id = @id

  -- This is a legacy application; find the appropriate surrogate key
  IF @id IS NULL AND @code IS NOT NULL
     SELECT Code FROM Users WHERE Users.id = @id

  -- Impossible code:
  UPDATE inserted SET inserted.code=@code, inserted.id=@id
END

Frage

Die 2 große Probleme ich habe, so weit sind:

  1. Ich kann keine "AFTER INSERT", weil NULL Einschränkungen wird der Einsatz nicht machen.
  2. Der „unmögliche Code“ Ich erwähnt ist, wie ich sauber Proxy die ursprüngliche Abfrage möge; Wenn die ursprüngliche Abfrage x hat, y, z Spalten in ihm oder nur x, ich möchte im Idealfall den gleichen Trigger diese zu tun. Und wenn ich eine weitere Spalte hinzufügen / löschen, würde ich den Auslöser wie funktional zu bleiben.

Jeder, der ein Codebeispiel, wo dies möglich sein könnte, oder auch eine alternative Lösung, um diese Spalten richtig gefüllt, auch für die Aufbewahrung, wenn nur einer der Werte zu SQL übergeben wird?

War es hilfreich?

Lösung 3

Nachdem das Problem schlafen, scheint dies die generic / wiederverwendbare Lösung zu sein, die ich mit in der SQL-Syntax kommen konnte. Es funktioniert gut, auch wenn beide Spalten eine NOT NULL Zurückhaltung haben, auch wenn Sie die Spalte „Sonstiges“ an alle in Ihrem Einsatz nicht verweisen.

CREATE TRIGGER tr_Access_Sync
ON Access
INSTEAD OF INSERT
AS 
BEGIN

    /*-- Create a temporary table to modify because "inserted" is read-only */
    /*-- "temp" is actually "#temp" but it throws off stackoverflow's syntax highlighting */
    SELECT * INTO temp FROM inserted

    /*-- If for whatever reason the secondary table has it's own identity column */
    /*-- we need to get rid of it from our #temp table to do an Insert later with identities on */
    ALTER TABLE temp DROP COLUMN oneToManyIdentity

    UPDATE temp 
    SET 
        UserCode = ISNULL(UserCode, (SELECT UserCode FROM Users U WHERE U.UserID = temp.UserID)),
        UserID = ISNULL(UserID, (SELECT UserID FROM Users U WHERE U.UserCode = temp.UserCode))

    INSERT INTO Access SELECT * FROM temp

END

Andere Tipps

Tricky Business ...

OK, zunächst einmal: Dieser Trigger wird nicht Arbeit in vielen Fällen:

SET @code = (SELECT inserted.code FROM inserted)
SET @id = (SELECT inserted.code FROM inserted)

Der Trigger kann mit einem Satz von Zeilen in der Inserted pseudo-Tabelle genannt werden -, die man machen Sie denn hier geht zu holen ?? Sie benötigen Trigger in einer solchen Art und Weise zu schreiben, dass es auch funktioniert, wenn Sie 10 Zeilen in der Inserted Tisch. Wenn eine SQL-Anweisung Einsätze 10 Zeilen, Ihre Trigger nicht zehnmal abgefeuert werden - eine für jede Zeile - aber nur einmal für die gesamte Charge - Sie müssen diese in nehmen Konto!

Zweiter Punkt: Ich würde versuchen, die IDENTITY Felder der ID zu machen - dann werden sie immer einen Wert bekommen - auch für „Legacy“ Anwendungen. Diese „alten“ Anwendungen sollten stattdessen ein Vermächtnis Schlüssel liefern - so Sie gut es sein sollte. Die einzige Frage, die ich sehe und nicht wissen, wie Sie diese sind Einsätze aus einem bereits konvertierten App Griff - tun sie auch einen „alten Stil“ Legacy-Schlüssel zur Verfügung stellen? Wenn nicht - wie schnell benötigen Sie einen solchen Schlüssel haben?

Was ich denke, wäre über einen „Cleanupauftrag“, die die Tabelle überfahren würden und alle Zeilen mit einem NULL-Legacy-Schlüssel und dann für sie etwas sinnvollen Wert bieten. Machen dies zu einem regelmäßigen gespeicherte Prozedur, und führen Sie es jeden z.B. Tag, 4 Stunden, 30 Minuten - alles nach Ihren Bedürfnissen. Dann müssen Sie nicht mit Triggern umgehen und alle Einschränkungen sie haben.

Wäre es nicht möglich sein, die Schemaänderungen ‚bigbang‘ zu machen, sondern schaffen Blick auf die Spitze jener Tabellen, dass ‚verstecken‘ die Änderung?

Ich glaube, Sie finden Sie vielleicht einfach sind die Brüche zu einem späteren Zeitpunkt aufzuschieben: „Wir werden dieser Spalte eine Anwendung zu einem Zeitpunkt, verbitten“ - es könnte meine Naivität, aber ich kann nicht sehen, wie das ist immer zur Arbeit zu gehen.

Sicher, ein schlechtes Durcheinander kann auftreten, wenn verschiedene Anwendungen sind die Dinge anders tun?

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top