aximand
Goto Top

Delete-Trigger reagiert nicht wie erwartet SQL Express 2016

Hallo zusammen,

im Einsatz ist ein SQL Express 2016.

Es gibt eine Tabelle nnsImportOGSTMP in die Werte durch einen Excel-Import geschrieben werden. Die Tabelle hat 2 Primärschlüssel. Das TMP steht für temporär.
In dieser Tabelle gibt es einen Delete-Trigger der folgendes macht:

IF NOT EXISTS (Select nnsImportOGS.Rechnungsnummer, nnsImportOGS.Rechnungsposition, nnsImportOGS.Rechnungsdatum from nnsImportOGS where nnsImportOGS.rechnungsnummer  = Rechnungsnummer  and nnsImportOGS.Rechnungsposition = Rechnungsposition and nnsImportOGS.Rechnungsdatum = Rechnungsdatum)
     INSERT INTO nnsImportOGS 
 select * FROM Deleted

Sinngemäß sollen also die Daten in der "temporären Tabelle" nnsImportOGSTMP gelöscht werden.
Dabei soll in der "produktiven" Tabelle nnsImportOGS geprüft werden ob Rechnungsnummer, Rechnungsposition als auch Rechnungsdatum bereits existieren.
Wenn nicht, soll der Inhalt (*) aus der temporären (from Deleted) in die produktive Tabelle eingefügt werden.

Importiere ich jetzt über Excel z.B. 1000 Datensätze in die 'temporäre' Tabelle und lösche diese dann im Managementstudio über
delete from nnsImportOGSTMP
so werden diese 1000 Datensätze auch korrekter Weise in die produktive (leere) Tabelle kopiert und die TMP wird geleert.

Leere ich die produktive Tabelle und wiederhole den Import der 1000 Datensätze und lösche die obersten 300 über
delete Top(300) from nnsImportOGSTMP
so werden diese 300 Datensätze gelöscht und 300 Datensätze in die produktive Tabelle kopiert.

Übrig bleiben in der TMP 700 Datensätze.

Wiederhole ich jetzt wahlweise mit einem Top(n) oder einem kompletten "delete from", dann werden die Daten in der TMP gelöscht, aber diese Datensätze nicht in die produktive Tabelle kopiert, in der bereits die 300 anderen Datensätze liegen.

Primärschlüsselverletzungen sind ausgeschlossen.


Kann sich da jemand einen Reim drauf machen?

Content-ID: 444230

Url: https://administrator.de/contentid/444230

Ausgedruckt am: 22.11.2024 um 08:11 Uhr

ukulele-7
Lösung ukulele-7 25.04.2019 aktualisiert um 09:43:08 Uhr
Goto Top
Also ich würde sagen du scheiterst schon in der IF-Clause, sofern es hier nicht eine MSSQL Funktion gibt die mir nicht geläufig ist.

Du greifst mit deinem Select nur auf die Haupttabelle zu und vergleichst die Spalten mit sich selbst, solange also Datensätze in der Haupttabelle existieren gibt dein Select immer ein "existiert" zurück und damit passiert erstmal gar nichts.

Du müsstest entweder die Temp-Tabelle oder, wie in Triggern eigentlich sinnvoller, die INSERTED / DELETED-Tabellen mit der Haupttabelle joinen und dann auf Dinge wie nnsImportOGS.rechnungsnummer = INSERTED.Rechnungsnummer prüfen.

Ein weiterer Knackpunkt ist dann in jedem Fall das, sobald eine Zeile deine Bedingung erfüllt, sich das auf alle Datensätze der Tabelle oder des Vorganges bezieht. Der Trigger löst nämlich nur einmal pro Insert/Update/Delete aus und nicht einmal pro Datensatz wie man das z.B. in MySQL macht. Da ist es wenig sinnvoll mit einem IF EXISTS für alle Datensätze zu arbeiten sondern du müsstest das ganze in der Select-Anweisung für den INSERT berücksichtigen (sprich dort den Join einbauen).
SELECT * FROM DELETED LEFT JOIN nnsImportOGS ON nnsImportOGS.rechnungsnummer  = DELETED.Rechnungsnummer  and nnsImportOGS.Rechnungsposition = DELETED.Rechnungsposition and nnsImportOGS.Rechnungsdatum = DELETED.Rechnungsdatum WHERE nnsImportOGS.rechnungsnummer IS NULL AND nnsImportOGS.Rechnungsposition IS NULL AND nnsImportOGS.Rechnungsdatum IS NULL
--LEFT OUTER JOIN with exclusion
Natürlich nicht mit INSERT INTO nnsImportOGS SELECT * sondern mit expliziten Spaltennamen arbeiten, sowohl im Select als auch im Insert, ich hoffe das ist klar.
Aximand
Aximand 25.04.2019 um 13:31:18 Uhr
Goto Top
Danke,

hat mich auf den richtigen Weg gebracht, nun läuft es ;)