2010-02-04 10 views
5

Wir führen eine Datenbankmigration zu SQL Server durch, und zur Unterstützung einer Legacy-App haben wir in der SQL Server-Tabelle Ansichten definiert, die Daten wie die Legacy-App erwarten.Verwenden von Standardwerten in einem INSTEAD OF INSERT-Trigger

Wir haben jedoch Probleme mit INSTEAD OF INSERT-Triggern, die für diese Sichten definiert wurden, wenn die Felder Standardwerte haben können.

Ich werde versuchen, ein Beispiel zu geben.

Eine Tabelle in der Datenbank hat 3 Felder, a, b und c. c ist brandneu, die Alt-App weiß nichts darüber, also haben wir auch eine Ansicht mit 2 Feldern, a und b.

Wenn die Legacy-Anwendung versucht, einen Wert in seiner Ansicht einzufügen, verwenden wir ein STATT INSERT-Trigger den Wert zu suchen, der in Feld c, so etwas wie das gehen sollte: von

INSERT INTO realTable(a, b, c) SELECT Inserted.a, Inserted.b, Calculated.C FROM... 

(Die Details die Suche ist nicht relevant.)

Dieser Trigger funktioniert gut, es sei denn Feld b hat einen Standardwert. Dies liegt daran, wenn die Abfrage

INSERT INTO legacyView(a) VALUES (123) 

ausgeführt wird, dann in dem Trigger, Inserted.b NULL ist, nicht Standardwert b. Jetzt habe ich ein Problem, weil ich nicht dem Unterschied die obige Abfrage sagen kann, was den Standardwert in b setzen würde, und dies:

INSERT INTO legacyView(a,b) VALUES (123, NULL) 

Auch wenn b war nicht NULLABLE, ich weiß nicht, Wie schreibe ich die INSERT-Abfrage in den Trigger, so dass, wenn ein Wert für b zur Verfügung gestellt wurde, wird es im Trigger verwendet, aber wenn nicht, wird stattdessen der Standardwert verwendet.

EDIT: hinzugefügt, dass ich lieber nicht die Standardwerte im Trigger duplizieren würde. Die Standardwerte sind bereits im Datenbankschema, ich würde hoffen, dass ich sie einfach direkt verwenden könnte.

+0

Zu wissen, dass alle Felder mit Standardwerten nicht nullbar sind, ist RIESIG! Ich hätte eine Lösung für dich finden können, wenn ich diese Information gewusst hätte. – ErikE

+0

Sorry Emtucifor, ich wusste zu der Zeit nicht, dass ich die Frage gestellt habe, dass wir keine Standardwerte auf Nullable-Feldern hatten. Was wäre deine Lösung gewesen? Wenn es gut ist, kann ich es immer noch aufwerten und vielleicht die akzeptierte Antwort ändern! –

Antwort

1

Paul: Ich habe dieses gelöst; schließlich. Bit einer schmutzigen Lösung und vielleicht nicht jedermanns Geschmack sein, aber ich bin ganz neu in SQL Server und dergleichen:

Im Instead_of_INSERT Trigger:

  1. Kopie der eingelegten virtuellen Datenstruktur der Tabelle ein temporäre Tabelle:

    SELECT * INTO aTempInserted FROM Inserted WHERE 1=2 
    
  2. eine Ansicht erstellen, die Standardeinschränkungen für die Ansicht der zugrunde liegende Tabelle (von Systemtabellen) und nutzen sie Aussagen zu bauen, um zu bestimmen, welche die Einschränkungen in der temporären Tabelle duplizieren:

  3. Verwenden Sie einen Cursor, um den abgerufenen Satz zu durchlaufen und jede Anweisung auszuführen. Dadurch bleibt eine temporäre Tabelle mit den gleichen Standardeinstellungen wie die Tabelle, in die sie eingefügt werden soll.

  4. einfügen Standardsatz in die temporäre Tabelle (alle Felder auf NULL festlegbare sind aus Inserted virtueller Tabelle erstellt):

    INSERT INTO aTempInserted DEFAULT VALUES 
    
  5. Kopieren Sie die Datensätze aus der Eingefügt virtuellen Tabelle in die zugrunde liegende Tabelle Sicht (wo würden sie ursprünglich eingefügt, wenn der Trigger dies nicht verhindert hat), tritt der temporären Tabelle bei, um Standardwerte zu liefern. Dies erfordert die Verwendung der COALESCE-Funktion, so dass nur unversorgt Werte vorgegeben werden:

    INSERT INTO realTable([a], [b], 
          SELECT COALESCE(I.[a], T.[a]), 
            COALESCE(I.[a], T.[b]) 
          FROM Inserted  AS I, 
            aTempInserted AS T 
    
  6. Löschen Sie die temporäre Tabelle

+0

Das ist fast da - Sie können immer noch nicht unterscheiden (in Schritt 5) zwischen einem NULL, weil der Wert nicht angegeben wurde (daher verwenden Sie den Standard), und einem NULL, weil ein NULL-Wert angegeben wurde (daher nicht verwenden) Das ist jedoch nur ein Problem, wenn Sie ein Nullable-Feld mit einem Standardwert haben, was wir meiner Meinung nach nicht tun, daher ist diese Antwort gut genug, um akzeptiert zu werden. " –

+0

Das stimmt. Es ist ein ziemlich komplizierter Ansatz. Sie können jedoch auch dort eingesetzt werden, wo weitere Joins/Verarbeitungen in den Einfügeanweisungen erforderlich sind. –

1

Einige Ideen:

  • Wenn die Legacy-Anwendung wird Spalte Listen für INSERTs Angabe und Spalten zu benennen anstatt SELECT * verwenden, können nicht Sie binden nur eine Standard-Spalte c und die Anwendung lassen Verwenden Sie Ihre ursprüngliche (modifizierte) Tabelle?

  • Wenn es eine Möglichkeit gäbe, die Legacy-Anwendung eine andere Ansicht oder Tabelle für ihre INSERTs als für SELECT oder DELETE zu verwenden, könnten Sie die erforderlichen Standardwerte für diese Tabelle verwenden und einen regulären After-Trigger verwenden die neuen Spalten über den realen Tisch.

  • Wie wäre es mit dem Verlassen der Originaltabelle und Hinzufügen Ihrer zusätzlichen Spalten in einer separaten Tabelle, die eine 1-1 Beziehung mit dem Original hat? Erstellen Sie dann eine Ansicht, die diese beiden Tabellen kombiniert, und fügen Sie anstelle dieser Trigger geeignete Trigger hinzu, um alle Datenoperationen zu verarbeiten, die über die beiden Tabellen verteilt sind. Mir ist klar, dass dies Auswirkungen auf die Leistung hat, aber es könnte der einzige Weg sein, das Problem zu umgehen. Dies wäre ein idealer Fall für eine materialisierte Ansicht, die Aktualisierungen verlangsamen würde, aber das Ergebnis genau wie eine Tabelle für Lesevorgänge ausführen lässt. (Materialisierten Ansichten eignen sich am besten zum inneren Joins und erfordern keine Aggregation. Sie stellen auch Schemasperren auf den Quellentabellen.)

  • Ich habe in ein ähnliches Problem laufen, wo ich nicht den Unterschied zwischen absichtlich NULL-Werte sagen könnte, und übersprungen Spalten in einem statt UPDATE-Trigger in einer Ansicht.Ich habe schließlich einen INSERT-Trigger für die Ansicht gemacht, um Einfügungen in Aktualisierungen zu konvertieren (wenn der Schlüssel bereits existierte, war es ein Update, ansonsten war es ein Einfügevorgang). Auch wenn dir das nicht direkt helfen wird, könnte es dir Ideen für dich oder andere geben.

+0

Vielen Dank für diese Kommentare, ich kann nicht auf etwas besonderes zeigen, das geholfen hat, aber es hat uns weniger fühlen lassen, als ob wir eine Ziegelmauer getroffen hätten! –

0

Was ist so etwas wie dieses ??? mit:

insert into realtable 
values inserted.a, isnull(inserted.b, DEFAULT), computedC 
from inserted