Default-Wert immer bei Insert setzen
-
Freitag, 27. April 2012 13:32
Hallo
In einer Tabelle habe ich eine Spalte mit DEFAULT NEWID() definiert. Damit gibt es zu jedem Datensatz eine eindeutige UID welche bei späteren Änderungen über das Programm einen neuen Wert erhält.
Durch ein Partner-Modul, bei welchem ein Datensatz kopiert und neu eingefügt wird, wird diese Spalte nicht geändert und würde so die gleiche UID bekommen, wie der 1. Datensatz(wird verhindert, weil Index gesetzt).Ich müsste also beim Insert aus dem Partnermodul heraus auf DB-Ebene eine neue UID generieren können, welche beim Insert gesetzt wird und keine Indexverletzung bringt.
Jemand einen Tipp, damit diese Spalte nicht nur initialisert wird, wenn kein Wert gesetzt wird, sondern immer?
Gruss Christoph
Alle Antworten
-
Freitag, 27. April 2012 13:40
Hallo Christoph,
über ein INSTEAD OF Trigger kannst Du sozusagen die Schreibaktion abfangen, die ID nach Deiner Business Logik neu erstellen und dann das eigentlich Schreiben in die Tabelle selbst vornehmen.
Siehe Entwerfen von INSTEAD OF-Triggern und Verwenden von INSTEAD OF-Triggern
Olaf Helper
* cogito ergo sum * errare humanum est * quote erat demonstrandum *
Wenn ich denke, ist das ein Fehler und das beweise ich täglich
Blog Xing
- Bearbeitet Olaf HelperMicrosoft Community Contributor Freitag, 27. April 2012 13:41
- Bearbeitet Olaf HelperMicrosoft Community Contributor Freitag, 27. April 2012 13:42 Links hinzugefügt.
-
Freitag, 27. April 2012 13:46ModeratorEin INSTEAD OF INSERT-Trigger. INSTEAD OF da sonst der Unique Constraint zuschlägt. Im Trigger prüfst du, ob die UID schon existiert und überschreibst sie in diesem Fall mit einer neuen UID.
Problem: Wenn ich Daten kopiere und ein OK bekomme erwarte ich im Besonderen bei solchen Spalten, das sich die Werte nicht ändern. Somit stellt sich die Frage, ob das Partnermodul dann überhaupt noch richtig funktionieren würde...
Für deinen Tipp: Ein Trigger nach dem Einfügen, der per virtueller INSERTED-Tabelle allen betroffenen Zeilen einen neuen Wert verpasst.
-
Freitag, 27. April 2012 15:11
Hallo zusammen
Werde es prüfen. Das mit dem geänderten Wert ist für die anderen Module kein Problem. Diese Spalte wird für CalDav-Schnittstelle genutzt und da bedeutet ein geänderter Wert nur, dass der Datensatz geändert wurde.
Gruss Christoph
-
Freitag, 27. April 2012 15:13Beantworter
Hallo Christoph,
neben der von Olaf und Stefan gegebenen Lösung via INSTEAD OF Trigger:
Verwende beim INSERT anstatt die Spalte zu übergeben, den Platzhalter DEFAULT in der VALUES Klausel,
womit die Default-Einschränkung (hier NEWID) verwendet wird -
oder aber verwende NEWID() als Ausdruck.Gruß Elmar
-
Freitag, 27. April 2012 15:18
Ich kann dem Partner schlecht vorschreiben, dass er das anders machen soll. Daher hätte ich lieber auf DB-Ebene das entsprechend umgesetzt
Gruss Christoph
-
Freitag, 27. April 2012 17:17
eine weitere Moeglichkeit ist, die Definition einer View und das Einfuegen der Daten ueber diese View fuer den Partner erzwingen.
Da geht z.b. falls er ein spezieller SQL Login benutzt und Du ein Schema definiert welches auf die View statt die Tabelle zeigt. Der Trigger ist dann nur noch auf der View notwendig und die performance leidet bei normalen Insert/Updates nicht.
siehe INSTEAD OF INSERT Triggers (erstes Beispiel "Create an INSTEAD OF INSERT trigger on the view")
Eine besserer Ansatz waere unter Umstaenden die Verwendung von rowversion da dann die SQL DB Engine garantiert, dass der Wert bei jedem INSERT resp. UPDATE geaendert wird. (ueberdies wird damit auch weniger Platz in der DB beansprucht).
Falls Du aber zwingend auf den Datentyp uniqueidentifier angewiesen bist, solltest Du klaeren, ob Du nicht besser newsequentialid anstelle von von newid verwenden kannst, da dann Index effizienter verwendet werden koennen.
Please use Mark as Answer if my post solved your problem and use Vote As Helpful if a post was useful.
-
Montag, 30. April 2012 14:12
Hallo Stefan
Bin jetzt am Trigger und wollte das wie folgt machen:
UPDATE inserted SET blcUID=NEWID()
INSERT INTO tdAddresses
SELECT * FROM insertedDas geht jetzt aber nicht: Die logischen Tabellen INSERTED und DELETED können nicht aktualisiert werden.
Weil in dieser Tabelle weitere Spalten dazukommen können, kann ich hier nicht einfach alle Spalten aufführen und bei der blcUID-Spalte das NewID angeben.
Gibt es eine Möglichkeit, dass ich den inserted-Wert ändern kann, bevor dann das INSERT selber gemacht wird?Gruss Christoph
-
Montag, 30. April 2012 14:58
Gibt es eine Möglichkeit, dass ich den inserted-Wert ändern kann, bevor dann das INSERT selber gemacht wird?
Hallo Christoph,
Du hast den INSTEAD OF Trigger noch nicht ganz verstanden. Der wird anstelle des eigentlichen Vorgangs ausgelöst und wie ich beim ersten Mal schon schrieb, musst Du das eigentliche Schreiben selbst vor nehmen.
Olaf Helper
* cogito ergo sum * errare humanum est * quote erat demonstrandum *
Wenn ich denke, ist das ein Fehler und das beweise ich täglich
Blog Xing -
Montag, 30. April 2012 18:36
Hallo Olaf
Denke, dass ich den Trigger schon verstanden habe. Wollte eben zuerst die Daten welche für das Einfügen bereitliegen anpassen und dann das Insert ausführen und da ich nicht weis, wie die Spalten später oder durch Partneranpassungen aussehen, müsste ich das Insert mit * machen.
Gruss Christoph
-
Dienstag, 1. Mai 2012 03:13
Hallo Christoph
chmav wrote:
Bin jetzt am Trigger und wollte das wie folgt machen:
UPDATE inserted SET blcUID=NEWID()
INSERT INTO tdAddresses
SELECT * FROM inserted
Das geht jetzt aber nicht: Die logischen Tabellen INSERTED und DELETED
können nicht aktualisiert werden.Du solltest auch nicht in die Konzepttabelle INSERTED reinschreiben, sondern - das ist ja der Grund für den INSTEAD OF INSERT (Anstelle des Hinzufügens) Trigger den Datensatz direkt in die Tabelle wegschreiben. Es spricht aber (ausser der Performance) nichts dagegen, eine temporäre Tabelle anzulegen, welche genau der Tabelle INSERTED entspricht, deren Inhalt zu ändern und anschliessend dann das Ergebnis in die Zieltabelle wegzuschreiben.
Hier ein Beispiel
CREATE TRIGGER tdAdresses_InsteadOfInsert ON tdAdresses INSTEAD OF INSERT AS BEGIN SET NOCOUNT ON SELECT * INTO #TEMPTABLE FROM INSERTED UPDATE #TEMPTABLE SET blcUID = NEWID() INSERT INTO tdAdresses SELECT * FROM #TEMPTABLE DROP TABLE #TEMPTABLE END
Gruss
Henry- Als Antwort markiert chmav Dienstag, 1. Mai 2012 09:28
-
Dienstag, 1. Mai 2012 09:11
Hallo Henry
An eine solche Lösung habe ich auch geacht, wollte aber zuerst sicher gehen, dass es wirklich keine Möglichkeit gibt, das direkt über die INSERTED-Tabelle zu machen.
Besten Dank Euch allen
Gruss Christoph
-
Dienstag, 1. Mai 2012 09:18
Hallo Christoph
chmav wrote:
An eine solche Lösung habe ich auch geacht, wollte aber zuerst sicher
gehen, dass es wirklich keine Möglichkeit gibt, das direkt über die
INSERTED-Tabelle zu machen.Da Du ja hier nicht mit riesigen Multirow Inserts, sondern wohl vorallem mit einzelnen Records konfrontiert wirst, sollte das soweit ok sein. Die lokale temporäre Tabelle wird - solange genügend Platz vorhanden ist - nur im Speicher angelegt und muss nicht physisch in die Temp DB geschrieben werden. Bezüglich Performance würde ich hier also wegen der lokalen temporären Tabelle keine allzugrossen Schwierigkeiten erwarten. Dafür bist Du sicher, dass du immer eine UID drin hast, auch wenn Deine Partner mit was anderem daher kommen. Diese könnten dann allerdings - abhängig vom System, das sie benutzen - mit der veränderten blcUID Probleme bekommen. Falls z.B. Access den Insert macht, müsste im Form_AfterUpdate sichergestellt werden, dass der Datensatz neu eingelesen wird, da sonst Access davon ausgeht, dass immer noch sein Schlüssel drin steht. Das sind dann aber eher die Probleme, mit denen die Partner kämpfen müssen, datenbankseitig sollte das so ok sein.
Gruss
Henry -
Dienstag, 1. Mai 2012 09:19
dass es wirklich keine Möglichkeit gibt, das direkt über die INSERTED-Tabelle zu machen
Hallo Christoph,
Nein, Du schreibst die Daten eben nicht in die virtuelle Tabellle INSERTED, sondern in die eigentlich Zieltabelle.
Olaf Helper
* cogito ergo sum * errare humanum est * quote erat demonstrandum *
Wenn ich denke, ist das ein Fehler und das beweise ich täglich
Blog Xing -
Dienstag, 1. Mai 2012 09:26

