Discussion:
Trigger wirken nicht bei Update von mehreren Zeilen
(zu alt für eine Antwort)
2005-09-26 07:45:48 UTC
Permalink
Hallo NG!

In einer relationalen Datenbank soll es ja des öfteren 1:n-Beziehungen
geben...

Da der MS SQL Server Beziehungen aber nicht allzu toll unterstützt, haben
wir in unserer Datenbank die Integritätsprüfung über Trigger realisiert. Das
funktioniert ganz gut, solange nur ein Datensatz geändert/gelöscht wird.
Werden aber mehrere Datensätze auf einmal geändert ("UPDATE Tabelle
SET Feld = Replace(Feld, 'abc', 'xyz') WHERE Feld IN (...)"),
dann wirkt der Trigger anscheinend nur für einen der geänderten Datensätze.

Enthält die "deleted" - Tabelle immer nur den letzten oder alle geänderten
Datensätze, die man dann in einer Schleife durchlaufen kann? Wenn ja wie?

Ich habe bisher immer nur Beispiele gefunden, die davon ausgehen, dass nur
ein Datensatz betroffen ist.


Mit freundlichen Grüßen
Daniel Barisch
Jürgen Volke
2005-09-26 08:14:00 UTC
Permalink
Hallo Daniel
Post by
In einer relationalen Datenbank soll es ja des öfteren 1:n-Beziehungen
geben...
Da der MS SQL Server Beziehungen aber nicht allzu toll unterstützt,
haben wir in unserer Datenbank die Integritätsprüfung über Trigger
realisiert. Das funktioniert ganz gut, solange nur ein Datensatz
geändert/gelöscht wird. Werden aber mehrere Datensätze auf einmal
geändert ("UPDATE Tabelle SET Feld = Replace(Feld, 'abc', 'xyz') WHERE Feld IN (...)"),
dann wirkt der Trigger anscheinend nur für einen der geänderten Datensätze.
Enthält die "deleted" - Tabelle immer nur den letzten oder alle
geänderten Datensätze, die man dann in einer Schleife durchlaufen
kann? Wenn ja wie?
da stehen schon alle drin

UPDATE T SET F = .. FROM DeineTabelle T inner join deleted d
ON T.Id = d.Id

wenn ID dein PK ist.

HTH Jürgen
2005-09-26 08:52:45 UTC
Permalink
Hallo Jürgen!

Erstmal vielen Dank für die Antwort!

Allerdings trifft das glaub ich noch nicht ganz das, was ich meinte. Oder
ich hab noch'n Brett vorm Kopf...
Post by Jürgen Volke
Post by
"UPDATE Tabelle SET Feld = Replace(Feld, 'abc', 'xyz') WHERE Feld IN
(...)"
sollte eigentlich eher ein Beispiel sein, für eine Anweisung, die den
Trigger auslöst. Bisher stand dann im Trigger (AFTER UPDATE) ungefähr

DECLARE @new varchar(...)
SELECT DISTINCT @new = PKField FROM inserted

-- (Update()-, NotNull- usw. -Prüfungen)

UPDATE Detailtabelle SET FKFeld = @new WHERE FKFeld IN (SELECT Name FROM
deleted)

Das IN-Konstrukt wird dabei eigentlich eher verwendet, um das etwas
universeller zu halten und nicht nach Datentp (String/Nicht-String)
unterscheiden zu müssen, jedoch nicht um wirklich mehrere Datensätze
auszuwählen.
Post by Jürgen Volke
Post by
Enthält die "deleted" - Tabelle immer nur den letzten oder alle
geänderten Datensätze, die man dann in einer Schleife durchlaufen
kann? Wenn ja wie?
da stehen schon alle drin
UPDATE T SET F = .. FROM DeineTabelle T inner join deleted d
ON T.Id = d.Id
Wenn ich Deinem Beispiel folgen will, dann müsste ich doch auch noch einen
Join zur inserted-Tabelle machen und dann für "..." sowas wie
"inserted.PKFeld" schreiben, oder? Aber wie kann ich so einen Join setzen?
Weder die zu ändernde Tabelle, noch die deleted-Tabelle wissen doch in dem
Moment, welcher neue Wert in der inserted-Tabelle steht, oder?


Mit freundlichen Grüßen
Daniel Barisch
Jürgen Volke
2005-09-26 09:10:57 UTC
Permalink
Hallo Daniel
Post by
Erstmal vielen Dank für die Antwort!
Allerdings trifft das glaub ich noch nicht ganz das, was ich meinte.
Oder ich hab noch'n Brett vorm Kopf...
kann schon sein *g*
Post by
Post by Jürgen Volke
Post by
"UPDATE Tabelle SET Feld = Replace(Feld, 'abc', 'xyz') WHERE Feld IN
(...)"
sollte eigentlich eher ein Beispiel sein, für eine Anweisung, die den
Trigger auslöst. Bisher stand dann im Trigger (AFTER UPDATE) ungefähr
-- (Update()-, NotNull- usw. -Prüfungen)
FROM deleted)
Das IN-Konstrukt wird dabei eigentlich eher verwendet, um das etwas
universeller zu halten und nicht nach Datentp (String/Nicht-String)
unterscheiden zu müssen, jedoch nicht um wirklich mehrere Datensätze
auszuwählen.
Post by Jürgen Volke
Post by
Enthält die "deleted" - Tabelle immer nur den letzten oder alle
geänderten Datensätze, die man dann in einer Schleife durchlaufen
kann? Wenn ja wie?
da stehen schon alle drin
UPDATE T SET F = .. FROM DeineTabelle T inner join deleted d
ON T.Id = d.Id
Wenn ich Deinem Beispiel folgen will, dann müsste ich doch auch noch
einen Join zur inserted-Tabelle machen und dann für "..." sowas wie
"inserted.PKFeld" schreiben, oder? Aber wie kann ich so einen Join
setzen? Weder die zu ändernde Tabelle, noch die deleted-Tabelle
wissen doch in dem Moment, welcher neue Wert in der inserted-Tabelle
steht, oder?
wenn du in deiner Tabelle einen PK hast, so existierten in inserted und deleted
Sätze mit diesem PK und Feldinhalt Neu bzw Alt für die restlichen Felder.

Bei einem Inner Join mit der Upzudatenen Tabelle ist es also egal ob dort
die Org-Tabelle oder insterted oder delete gejoint wird.

Gruß Jürgen
2005-09-26 09:28:35 UTC
Permalink
Hallo Jürgen!
Post by Jürgen Volke
Post by
Wenn ich Deinem Beispiel folgen will, dann müsste ich doch auch noch
einen Join zur inserted-Tabelle machen und dann für "..." sowas wie
"inserted.PKFeld" schreiben, oder? Aber wie kann ich so einen Join
setzen? Weder die zu ändernde Tabelle, noch die deleted-Tabelle
wissen doch in dem Moment, welcher neue Wert in der inserted-Tabelle
steht, oder?
wenn du in deiner Tabelle einen PK hast, so existierten in inserted und deleted
Sätze mit diesem PK und Feldinhalt Neu bzw Alt für die restlichen Felder.
Bei einem Inner Join mit der Upzudatenen Tabelle ist es also egal ob dort
die Org-Tabelle oder insterted oder delete gejoint wird.
Ja, aber eben nur so lange, wie eben nicht genau der Primärschlüssel
geändert wird....
(siehe anderer Thread)
Jens
2005-09-26 08:21:26 UTC
Permalink
Ein oft auftretendes Missverständnis, Trigger werden pro DML-Operation
und nicht pro Zeile ausgeführt, dein Code muß also diesen
Sachverhalt, das mehrere Zeilen in der Deleted / Inserted Tabelle
stehen, abfangen. mit Cursorn oder Schleifen würde ich nicht arbeiten,
da die meisten Befehle doch meistens Set-based ausgeführt werden
können (siehe beispiel von jürgen). In den seltesten Fällen musst Du
auch mal ein Schleifenkonstrukt verwenden, wenn Du z.B. für jede Zeile
eine Prozedur starten willst.


HTH, Jens Suessmeyer.
2005-09-26 09:00:48 UTC
Permalink
Hallo Jens
Post by Jens
Ein oft auftretendes Missverständnis, Trigger werden pro DML-Operation
und nicht pro Zeile ausgeführt,
Das ist mir jetzt klar. Danke.
Post by Jens
dein Code muß also diesen
Sachverhalt, das mehrere Zeilen in der Deleted / Inserted Tabelle
stehen, abfangen.
Post by Jens
mit Cursorn oder Schleifen würde ich nicht arbeiten,
Das will ich eigentlich auch lieber vermeiden
Post by Jens
da die meisten Befehle doch meistens Set-based ausgeführt werden
können (siehe beispiel von jürgen).
Aber dazu muss ich doch irgendwie eine Beziehung zwischen der deleted- und
der inserted-Tabelle herstellen, oder? Haben die vielleicht ein zusätzliches
Feld, was die Datensätze in beiden Tabellen einander zuordnet? Wenn die
auslösende Anweisung den Primärschlüssel ändert, dann kann das ja nicht über
selbigen funktionieren.

Mit freundlichen Grüßen
Daniel Barisch
Jürgen Volke
2005-09-26 09:12:34 UTC
Permalink
Hallo Daniel
Post by
Post by Jens
Ein oft auftretendes Missverständnis, Trigger werden pro
DML-Operation und nicht pro Zeile ausgeführt,
Das ist mir jetzt klar. Danke.
Post by Jens
dein Code muß also diesen
Sachverhalt, das mehrere Zeilen in der Deleted / Inserted Tabelle
stehen, abfangen.
Post by Jens
mit Cursorn oder Schleifen würde ich nicht arbeiten,
Das will ich eigentlich auch lieber vermeiden
Post by Jens
da die meisten Befehle doch meistens Set-based ausgeführt werden
können (siehe beispiel von jürgen).
Aber dazu muss ich doch irgendwie eine Beziehung zwischen der
deleted- und der inserted-Tabelle herstellen, oder? Haben die
vielleicht ein zusätzliches Feld, was die Datensätze in beiden
Tabellen einander zuordnet? Wenn die auslösende Anweisung den
Primärschlüssel ändert, dann kann das ja nicht über selbigen
funktionieren.
dann hast du wohl ein Design-Problem. Der PK sollte wohl eher nicht
änderbar sein.

Gruß Jürgen
2005-09-26 09:28:03 UTC
Permalink
Hallo Jürgen!
Post by Jürgen Volke
Post by
Aber dazu muss ich doch irgendwie eine Beziehung zwischen der
deleted- und der inserted-Tabelle herstellen, oder? Haben die
vielleicht ein zusätzliches Feld, was die Datensätze in beiden
Tabellen einander zuordnet? Wenn die auslösende Anweisung den
Primärschlüssel ändert, dann kann das ja nicht über selbigen
funktionieren.
Na aber genau darin liegt doch der Sinn eines Triggers zur Sicherstellung
der referentiellen Integrität. Wenn ich ein "losgelöstes" Feld ändere,
brauch ich doch keinen Trigger aufrufen, nur um mal in den Saal (die
Datenbank) zu schreien "Hey, hier hat einer ein für euch unwichtiges Feld
geändert."
Post by Jürgen Volke
dann hast du wohl ein Design-Problem. Der PK sollte wohl eher nicht
änderbar sein.
Sollte man das wirklich so knallhart sagen? Ich finds ehrlich gesagt nicht
toll, für jede Mastertabelle, die eigentlich nur eine Werte-Enumeration
darstellt, zusätzlich noch eine GUID o.ä. als Primärschlüssel zu defnieren.
Irgendwie wünsch ich mir doch wieder mein altes Access wieder. Da hat man
einfach ne Beziehung definiert und fertig...


Mit freundlichen Grüßen
Daniel Barisch
Jürgen Volke
2005-09-26 12:30:20 UTC
Permalink
Hallo Daniel
Post by
Post by Jürgen Volke
Post by
Aber dazu muss ich doch irgendwie eine Beziehung zwischen der
deleted- und der inserted-Tabelle herstellen, oder? Haben die
vielleicht ein zusätzliches Feld, was die Datensätze in beiden
Tabellen einander zuordnet? Wenn die auslösende Anweisung den
Primärschlüssel ändert, dann kann das ja nicht über selbigen
funktionieren.
Na aber genau darin liegt doch der Sinn eines Triggers zur
Sicherstellung der referentiellen Integrität. Wenn ich ein
"losgelöstes" Feld ändere, brauch ich doch keinen Trigger aufrufen,
nur um mal in den Saal (die Datenbank) zu schreien "Hey, hier hat
einer ein für euch unwichtiges Feld geändert."
Post by Jürgen Volke
dann hast du wohl ein Design-Problem. Der PK sollte wohl eher nicht
änderbar sein.
Sollte man das wirklich so knallhart sagen? Ich finds ehrlich gesagt
nicht toll, für jede Mastertabelle, die eigentlich nur eine
Werte-Enumeration darstellt, zusätzlich noch eine GUID o.ä. als
Primärschlüssel zu defnieren. Irgendwie wünsch ich mir doch wieder
mein altes Access wieder. Da hat man einfach ne Beziehung definiert
und fertig...
jetzt verstehe ich wiederum nicht ganz, wieso mehrere Datensätze auf
einen Schlag geändert werden, wenn es um die Ändeung des Primärschlüssels
geht. Das macht doch eigentlich nur Sinn, wenn es gezielt im Frontend pro Satz
gemacht wird. Und da gibt es IMHO auch nur einen Satz in inserted, bzw. deleted

Schreib uns doch mal die Beteiligten Tabellen mit den relevanten Feldern.
Vielleicht kann dir ja doch noch geholfen werden.

Gruß Jürgen
2005-09-26 12:51:38 UTC
Permalink
Hallo Jürgen!
Post by Jürgen Volke
Post by
Post by Jürgen Volke
dann hast du wohl ein Design-Problem. Der PK sollte wohl eher nicht
änderbar sein.
Sollte man das wirklich so knallhart sagen? Ich finds ehrlich gesagt
nicht toll, für jede Mastertabelle, die eigentlich nur eine
Werte-Enumeration darstellt, zusätzlich noch eine GUID o.ä. als
Primärschlüssel zu defnieren. Irgendwie wünsch ich mir doch wieder
mein altes Access wieder. Da hat man einfach ne Beziehung definiert
und fertig...
jetzt verstehe ich wiederum nicht ganz, wieso mehrere Datensätze auf
einen Schlag geändert werden, wenn es um die Ändeung des Primärschlüssels
geht. Das macht doch eigentlich nur Sinn, wenn es gezielt im Frontend pro Satz
gemacht wird. Und da gibt es IMHO auch nur einen Satz in inserted, bzw. deleted
Schreib uns doch mal die Beteiligten Tabellen mit den relevanten Feldern.
Vielleicht kann dir ja doch noch geholfen werden.
Ok, nehmen wir mal ein Beispiel: In der Datenbank sind ganz viele Adressen
gespeichert, jede Adresse kann einer Gruppe zugeordnet sein. Also erstelle
ich eine extra Tabelle für die Gruppen und eine entsprechende "Beziehung"
zwischen Adressgruppen.Name und Adressen.Gruppe. Und da fallen mir noch
etliche Beispiele aus unserer DB ein (Gruppen für Artikel/Mitarbeiter/...,
Zahlungsmittel, ...).
In der Regel wird natürlich nur ein Datensatz sauber im Frontend geändert,
dann gibt's da auch kein Problem. Aber wenn mir irgendwann irgendwelche
"Bennenungs-Konventionen" nicht mehr passen oder irgendwelche
Gesetzesänderungen dies erfordern, werde ich bemüht sein, möglichst
effizient mehrere Gruppen auf einmal umzubennen, geschickterweise per
SQL-UPDATE, weil's im FE aufgrund der DAU-Sicherheit etwas umständlicher
ist. Nur geht genau das eben bisher schief...

Muss ich dass doch per Schleife realisieren? Wenn ja, wo muss ich mich da
noch schlau machen, find nicht so recht den Ansatz... Kann ich
inserted-/deleted-Tabellen mit einem Cursor o.ä. öffnen und dann
durchlaufen? Der Index sollte doch in beiden Tabellen übereinstimmen, also
ich meine Reihe 8 aus deleted gehört zu Reihe 8 aus inserted?


Mit freundlichen Grüßen
Daniel Barisch
Jürgen Volke
2005-09-26 14:06:25 UTC
Permalink
Hallo Daniel
Post by
Post by Jürgen Volke
Post by
Post by Jürgen Volke
dann hast du wohl ein Design-Problem. Der PK sollte wohl eher nicht
änderbar sein.
Sollte man das wirklich so knallhart sagen? Ich finds ehrlich gesagt
nicht toll, für jede Mastertabelle, die eigentlich nur eine
Werte-Enumeration darstellt, zusätzlich noch eine GUID o.ä. als
Primärschlüssel zu defnieren. Irgendwie wünsch ich mir doch wieder
mein altes Access wieder. Da hat man einfach ne Beziehung definiert
und fertig...
jetzt verstehe ich wiederum nicht ganz, wieso mehrere Datensätze auf
einen Schlag geändert werden, wenn es um die Ändeung des
Primärschlüssels geht. Das macht doch eigentlich nur Sinn, wenn es
gezielt im Frontend pro Satz
gemacht wird. Und da gibt es IMHO auch nur einen Satz in inserted, bzw. deleted
Schreib uns doch mal die Beteiligten Tabellen mit den relevanten
Feldern. Vielleicht kann dir ja doch noch geholfen werden.
Ok, nehmen wir mal ein Beispiel: In der Datenbank sind ganz viele
Adressen gespeichert, jede Adresse kann einer Gruppe zugeordnet sein.
Also erstelle ich eine extra Tabelle für die Gruppen und eine
entsprechende "Beziehung" zwischen Adressgruppen.Name und
Adressen.Gruppe.
ich hätte da sie Tabelle tblAdressen mit dem dem INT-Feld GruppenId
und die Tabelle tblGruppen mit den beiden Feldern
ID (int PK), Bezeichnung
Dann kann ich die Bezeichnung beliebig abändern ohne in tblAdressen
irgend etwas ändern zu müssen
Post by
Und da fallen mir noch etliche Beispiele aus unserer
DB ein (Gruppen für Artikel/Mitarbeiter/..., Zahlungsmittel, ...).
In der Regel wird natürlich nur ein Datensatz sauber im Frontend
geändert, dann gibt's da auch kein Problem. Aber wenn mir irgendwann
irgendwelche "Bennenungs-Konventionen" nicht mehr passen oder
irgendwelche Gesetzesänderungen dies erfordern, werde ich bemüht
sein, möglichst effizient mehrere Gruppen auf einmal umzubennen,
geschickterweise per SQL-UPDATE, weil's im FE aufgrund der
DAU-Sicherheit etwas umständlicher ist. Nur geht genau das eben
bisher schief...
Muss ich dass doch per Schleife realisieren? Wenn ja, wo muss ich
mich da noch schlau machen, find nicht so recht den Ansatz... Kann ich
inserted-/deleted-Tabellen mit einem Cursor o.ä. öffnen und dann
durchlaufen? Der Index sollte doch in beiden Tabellen übereinstimmen,
also ich meine Reihe 8 aus deleted gehört zu Reihe 8 aus inserted?
da wär ich mir nicht sicher in einer relationalen Datenbank.

Gruß Jürgen
2005-09-26 14:32:58 UTC
Permalink
Hallo Jürgen!
Post by Jürgen Volke
Post by
Ok, nehmen wir mal ein Beispiel: In der Datenbank sind ganz viele
Adressen gespeichert, jede Adresse kann einer Gruppe zugeordnet sein.
Also erstelle ich eine extra Tabelle für die Gruppen und eine
entsprechende "Beziehung" zwischen Adressgruppen.Name und
Adressen.Gruppe.
ich hätte da sie Tabelle tblAdressen mit dem dem INT-Feld GruppenId
und die Tabelle tblGruppen mit den beiden Feldern
ID (int PK), Bezeichnung
Dann kann ich die Bezeichnung beliebig abändern ohne in tblAdressen
irgend etwas ändern zu müssen
Hätte ich eventuell auch, mir ist schon klar, dass das eher der
137.Normalform entspricht. Nur leider gehört uns die Datenbank nicht
alleine, wir bauen z.T. nur ein anderes (und natürlich besseres ;) Frontend
um die Daten.
Aber eigentlich wollen ich auch gar nicht mit solchen ID-Konstrukten
arbeiten, dann muss man sich nämlich an allen Stellen der Anwendung extra
darum kümmern, den "DisplayValue" zu ermitteln. Stell Dir nur mal eine
Adressen-Tabelle mit rund 13 Fremdschlüssel-Feldern vor - auf die
durchgeJOINte SELECT-Abfrage freu ich mich schon... Ich sehe da in einem
"ordentlichen" RDBMS einfach keine Notwendigkeit für. Hauptsache der PK ist
eindeutig und es ist Aufgabe des RDBMS dies auch in abhängigen Tabellen
durchzusetzen, wenn der sich ändert. In Access geht's doch auch (einfacher).
Post by Jürgen Volke
da wär ich mir nicht sicher in einer relationalen Datenbank.
Also definitiv nein oder weißt Du's momentan nicht besser?


Mit freundlichen Grüßen
Daniel Barisch
Stefan Hoffmann
2005-09-26 14:49:28 UTC
Permalink
tach Daniel,
Post by
Hätte ich eventuell auch, mir ist schon klar, dass das eher der
137.Normalform entspricht.
Blasphemie!
Post by
Aber eigentlich wollen ich auch gar nicht mit solchen ID-Konstrukten
arbeiten, dann muss man sich nämlich an allen Stellen der Anwendung extra
darum kümmern, den "DisplayValue" zu ermitteln.
Das ist tatsächlich ein Grund auf IDs zu verzichten. Wobei geschickte
Joins den Aufwand in Grenzen halte, will sagen, nicht allzu
performancefressend sind.
Post by
Ich sehe da in einem
"ordentlichen" RDBMS einfach keine Notwendigkeit für. Hauptsache der PK ist
eindeutig und es ist Aufgabe des RDBMS dies auch in abhängigen Tabellen
durchzusetzen, wenn der sich ändert.
Richtig. Im SQL Server ist das eine deklarative referenzielle Integrität
mit Aktualisierungsweitergabe.


mfG
--> stefan <--
2005-09-26 14:56:03 UTC
Permalink
Hallo Stefan!
Post by Stefan Hoffmann
Post by
Hätte ich eventuell auch, mir ist schon klar, dass das eher der
137.Normalform entspricht.
Blasphemie!
Na dann nagel mich mal besser ans Kreuzprodukt...
Post by Stefan Hoffmann
Post by
Aber eigentlich wollen ich auch gar nicht mit solchen ID-Konstrukten
arbeiten, dann muss man sich nämlich an allen Stellen der Anwendung extra
darum kümmern, den "DisplayValue" zu ermitteln.
Das ist tatsächlich ein Grund auf IDs zu verzichten. Wobei geschickte
Joins den Aufwand in Grenzen halte, will sagen, nicht allzu
performancefressend sind.
Oh danke, an die Performance hatte ich hierbei noch nichtmal gedacht, bis
jetzt ging's mir nur um den Schreibaufwand.
Post by Stefan Hoffmann
Post by
Ich sehe da in einem "ordentlichen" RDBMS einfach keine Notwendigkeit
für. Hauptsache der PK ist eindeutig und es ist Aufgabe des RDBMS dies
auch in abhängigen Tabellen durchzusetzen, wenn der sich ändert.
Richtig. Im SQL Server ist das eine deklarative referenzielle Integrität
mit Aktualisierungsweitergabe.
Das werd ich mir wohl nochmal ansehen müssen. Wie gesagt, das Problem sind
hierbei Fremdschlüssel über mehrere Felder.


Mit freundlichen Grüßen
Daniel Barisch
Jürgen Volke
2005-09-26 15:03:01 UTC
Permalink
Hallo Daniel
Post by
Hätte ich eventuell auch, mir ist schon klar, dass das eher der
137.Normalform entspricht. Nur leider gehört uns die Datenbank nicht
alleine, wir bauen z.T. nur ein anderes (und natürlich besseres ;)
Frontend um die Daten.
Aber eigentlich wollen ich auch gar nicht mit solchen ID-Konstrukten
arbeiten, dann muss man sich nämlich an allen Stellen der Anwendung
extra darum kümmern, den "DisplayValue" zu ermitteln. Stell Dir nur
mal eine Adressen-Tabelle mit rund 13 Fremdschlüssel-Feldern vor -
auf die durchgeJOINte SELECT-Abfrage freu ich mich schon...
Auf dem Server wird da gar nix gejoint, wenn der Datensatz im FE änderbar sein soll.
Die Felder werden als Kombifelder realisiert (mit der Option weitere Einträge hinzufügen
zu dürfen).
Post by
Post by Jürgen Volke
da wär ich mir nicht sicher in einer relationalen Datenbank.
Also definitiv nein oder weißt Du's momentan nicht besser?
ich würde mich nicht darauf verlassen wollen!

Gruß Jürgen
Stefan Hoffmann
2005-09-26 09:24:21 UTC
Permalink
tach Daniel,
Post by
In einer relationalen Datenbank soll es ja des öfteren 1:n-Beziehungen
geben...
Da der MS SQL Server Beziehungen aber nicht allzu toll unterstützt, haben
wir in unserer Datenbank die Integritätsprüfung über Trigger realisiert.
Was meinst du mit "nicht allzu toll unterstüzt"?

DRI kann er, und ich kenne keinen Fall, in dem Trigger die besser
alternative für die Wahrung der Integrität sind.


mfG
--> stefan <--
2005-09-26 09:50:47 UTC
Permalink
Hallo Stefan!
Post by Stefan Hoffmann
Post by
In einer relationalen Datenbank soll es ja des öfteren 1:n-Beziehungen
geben...
Da der MS SQL Server Beziehungen aber nicht allzu toll unterstützt, haben
wir in unserer Datenbank die Integritätsprüfung über Trigger realisiert.
Was meinst du mit "nicht allzu toll unterstüzt"?
Na was ist mit Beziehungen über mehrer Felder? Meines Erachtens nach geht
das nicht, oder? Wenn der Primärschlüssel über mehrere Felder geht, dann
muss ja auch die Beziehung entsprechend definiert werden.

Und jetzt schlag mich bitte nicht, weil PK's über mehrere Felder ja eh böse
sind... Das kann man sich leider nicht immer aussuchen, da einem die
Datenbank nicht immer gehört.


Mit freundlichen Grüßen
Daniel Barisch
Dieter Noeth
2005-09-26 11:24:57 UTC
Permalink
Post by
Na was ist mit Beziehungen über mehrer Felder? Meines Erachtens nach geht
das nicht, oder? Wenn der Primärschlüssel über mehrere Felder geht, dann
muss ja auch die Beziehung entsprechend definiert werden.
Es gibt Constraints auf Spalten- und auf Tabellenebene. Den PK auf
Tabellenebene hast du ja wohl schon entdeckt, dann schau doch noch mal
die FK-Syntax etwas genauer an ;-)
Post by
Und jetzt schlag mich bitte nicht, weil PK's über mehrere Felder ja eh böse
sind...
Nichts ist von Natur aus pöse...

Dieter
Günther Bach
2005-09-26 15:58:02 UTC
Permalink
Post by
In einer relationalen Datenbank soll es ja des öfteren 1:n-Beziehungen
geben...
Da der MS SQL Server Beziehungen aber nicht allzu toll unterstützt, haben
wir in unserer Datenbank die Integritätsprüfung über Trigger realisiert. Das
funktioniert ganz gut, solange nur ein Datensatz geändert/gelöscht wird.
Werden aber mehrere Datensätze auf einmal geändert ("UPDATE Tabelle
SET Feld = Replace(Feld, 'abc', 'xyz') WHERE Feld IN (...)"),
dann wirkt der Trigger anscheinend nur für einen der geänderten Datensätze.
Enthält die "deleted" - Tabelle immer nur den letzten oder alle geänderten
Datensätze, die man dann in einer Schleife durchlaufen kann? Wenn ja wie?
Ich habe bisher immer nur Beispiele gefunden, die davon ausgehen, dass nur
ein Datensatz betroffen ist.
Unsere Trigger sehen so aus, laufen also in einer Schleife:

CREATE TRIGGER [xxxx_UPDATE] ON dbo.tab_xxxx
INSTEAD OF UPDATE
AS
BEGIN
DECLARE xx_update_cursor CURSOR LOCAL FOR SELECT xx_id FROM
inserted

DECLARE @IntID int

OPEN xx_update_cursor

FETCH NEXT FROM xx_update_cursor INTO @IntID

WHILE @@FETCH_STATUS = 0
BEGIN

-- Hier jetzt die ganzen SQL-Abfragen
UPDATE tab_xxxx
SET
tab_xxxx.xx_id = i.x_id
FROM inserted i
WHERE tab_xxxx.xx_id = @IntID AND i.xx_id = @IntID
-- usw.....

FETCH NEXT FROM xx_update_cursor INTO @IntID
END
CLOSE xx_update_cursor
DEALLOCATE xx_update_cursor
END
2005-09-27 05:41:43 UTC
Permalink
Hallo Günther!
Post by Günther Bach
CREATE TRIGGER [xxxx_UPDATE] ON dbo.tab_xxxx
INSTEAD OF UPDATE
AS
BEGIN
DECLARE xx_update_cursor CURSOR LOCAL FOR SELECT xx_id FROM
inserted
OPEN xx_update_cursor
BEGIN
-- Hier jetzt die ganzen SQL-Abfragen
UPDATE tab_xxxx
SET
tab_xxxx.xx_id = i.x_id
FROM inserted i
-- usw.....
END
CLOSE xx_update_cursor
DEALLOCATE xx_update_cursor
END
Na das sieht doch schon mehr nach dem aus, was ich die ganze Zeit gesucht
habe, danke!
Aber bist Du Dir sicher, dass das so funktioniert? Irgendwie fehlt mir da
ein Bezug zur deleted-Tabelle, um die richtigen Detaildatensätze
auszuwählen. Die Bedingung "... WHERE tab_xxxx.xx_id = @IntID AND ..." kann
doch für meine Begriffe zu diesem Zeitpunkt für keinen (Detail-)Datensatz
zutreffen.


Mit freundlichen Grüßen
Daniel Barisch
Elmar Boye
2005-09-27 09:02:11 UTC
Permalink
Hallo Daniel,

ich hänge mich mal hier rein...

Daniel Barisch <Daniel Barisch> schrieb ...
Post by
Post by Günther Bach
CREATE TRIGGER [xxxx_UPDATE] ON dbo.tab_xxxx
INSTEAD OF UPDATE
Na das sieht doch schon mehr nach dem aus, was ich die ganze Zeit
gesucht habe, danke!
Aber bist Du Dir sicher, dass das so funktioniert?
Irgendwie fehlt mir da ein Bezug zur deleted-Tabelle,
um die richtigen Detaildatensätze auszuwählen.
Das funktioniert genausowenig wie bei einem normalen Trigger.

Um die Frage an anderer Stelle zu beantworten:
Es gibt keine definierte Reihenfolge in den inserted und deleted
Pseudotabellen. Die Daten werden vielmehr direkt aus dem
Protokolldaten gewonnen und so zusammengestellt wie sie
dort vorgefunden werden.

Und wenn Du keinen Primärschlüssel hast, gibt es in SQL
per Definitionem keine Beziehung zwischen zwei Tabellen.
Langes Arbeiten mit Access ISAM Logik lässt das einen
schon mal vergessen ;-).

Somit ist eine Änderung von Primärschlüssel Spalten
(sofern kein alternativer Unique Schlüssel existiert)
im Trigger nur für eine Zeile möglich.

Was im übrigen bei den meisten Anwendungsfällen keine
Einschränkung sein dürfte, da die Änderung dort immer
Zeilenweise erfolgt. Nur etwas wie
UPDATE Tabelle SET PK = PK + 4711
geht nicht (was aber die extreme Ausnahme sein sollte).

Testen kann man das in etwa:
IF (SELECT COUNT(*) FROM inserted) <>
(SELECT COUNT(*) FROM inserted
INNER JOIN deleted ON inserted.PK = deleted.PK)
BEGIN
-- dieses IF weglassen, wenn man es gar nicht erlauben will
IF (SELECT COUNT(*) FROM inserted) > 1
BEGIN
RAISERROR('Änderung des Primärschlüssels nur für eine Zeile erlaubt.', 16, 1)
ROLLBACK TRAN
RETURN
END
END

Praktisch würde ich auf das Ändern des Primärschlüssels
eher verzichten.
Schon gerade bei öffentlich zugänglichen, denn die notiert
der eine oder andere auf einem Blatt Papier (und da wird
nie eine Änderung kaskadiert)

Und wenns unbedingt sein muss: Besser eine Kopie der
bestehenden Datenzeilen anzulegen und anschliessend
die alten löschen.

Mehr dazu habe ich in der Vergangenheit von mir gegeben:
http://groups.google.com/groups?as_q=trigger+prim%C3%A4rschl%C3%BCssel+&as_ugroup=microsoft.public.de.sqlserver&as_uauthors=Elmar+Boye

Gruss
Elmar
2005-09-27 10:12:09 UTC
Permalink
Hallo Elmar!
Post by Elmar Boye
ich hänge mich mal hier rein...
Aber gerne doch...
Post by Elmar Boye
Es gibt keine definierte Reihenfolge in den inserted und deleted
Pseudotabellen. Die Daten werden vielmehr direkt aus dem
Protokolldaten gewonnen und so zusammengestellt wie sie
dort vorgefunden werden.
Danke, damit wär das denk ich ausreichend beantwortet.
Post by Elmar Boye
Und wenn Du keinen Primärschlüssel hast, gibt es in SQL
per Definitionem keine Beziehung zwischen zwei Tabellen.
Langes Arbeiten mit Access ISAM Logik lässt das einen
schon mal vergessen ;-).
Primärschlüssel haben wir ja, nur dass das eben auch "änderbare" Text-Felder
sind oder die sich auch mal aus mehreren Feldern zusammensetzen.
Post by Elmar Boye
Somit ist eine Änderung von Primärschlüssel Spalten
(sofern kein alternativer Unique Schlüssel existiert)
im Trigger nur für eine Zeile möglich.
Wie bereits in den anderen Postings gesagt, wurde auf ein "ordentliches"
DB-Design mit GUID-Schlüsseln bewusst verzichtet (Entwicklungsaufwand,
Performance, ...).
Post by Elmar Boye
Was im übrigen bei den meisten Anwendungsfällen keine
Einschränkung sein dürfte, da die Änderung dort immer
Zeilenweise erfolgt. Nur etwas wie
UPDATE Tabelle SET PK = PK + 4711
geht nicht (was aber die extreme Ausnahme sein sollte).
Dass das eher die Ausnahme ist, hatte ich ja schon geschrieben. Aber bei
einer DB mit gut 150 Tabellen kann diese Ausnahme schon öfter mal vorkommen.
In diesen Fällen soll es halt möglichst effizient zu bewerkstelligen
sein, vor allem ohne dass ich mir dann Gedanken machen muss, dass es hier
anders als nur für einen Datensatz funktioniert.
Post by Elmar Boye
Praktisch würde ich auf das Ändern des Primärschlüssels
eher verzichten.
Schon gerade bei öffentlich zugänglichen, denn die notiert
der eine oder andere auf einem Blatt Papier (und da wird
nie eine Änderung kaskadiert)
Über das Frontend ist das ja für den normalen Nutzer auch nur datensatzweise
möglich. Aber das Erstellen einer SQL-Anweisung "zur Datenpflege" kann man
dann halt für den speziellen Fall als Dienstleistung anbieten.
Post by Elmar Boye
Und wenns unbedingt sein muss: Besser eine Kopie der
bestehenden Datenzeilen anzulegen und anschliessend
die alten löschen.
Na ja, dass ist vielleicht gar nicht immer so einfach möglich. Eine Kopie
von dem einen Masterdatensatz (der Entitätswert) ist relativ sinnlos und für
die 50.000 Detaildatensätze musst Du dir dann nen neuen Primärschlüssel
überlegen.


Ich denke das Thema ist für mich ausreichend beantwortet. Mir sind nun die
Gründe bekannt, warum es so nicht zu realiseren geht. Wenn ich das für
spezielle Fälle unbedingt benötige, dann kann dafür immer noch eine SP zum
Einsatz kommen. Ich denke da so an Übergabe einer WHERE-Klausel als
Parameter und einen CURSOR. Und zur Not kann ja auch immer noch Client-Logik
verwendet werden...

Vielen Dank an alle!


Mit freundlichen Grüßen
Daniel Barisch
Elmar Boye
2005-09-27 14:07:28 UTC
Permalink
Hallo Daniel,

Daniel Barisch <Daniel Barisch> schrieb ...
Post by
Post by Elmar Boye
Und wenn Du keinen Primärschlüssel hast, gibt es in SQL
per Definitionem keine Beziehung zwischen zwei Tabellen.
Langes Arbeiten mit Access ISAM Logik lässt das einen
schon mal vergessen ;-).
Primärschlüssel haben wir ja, nur dass das eben auch "änderbare"
Text-Felder sind oder die sich auch mal aus mehreren Feldern
zusammensetzen.
In einer normalisierten Datenbank sollte das normalerweise
nicht vorkommen müssen.
Und eine Artikel/Kundennummer etc. gerade mal ändern
können, ist aus vielerlei Gründen schon abseits der
Datenbank tabu.
Post by
Post by Elmar Boye
Somit ist eine Änderung von Primärschlüssel Spalten
(sofern kein alternativer Unique Schlüssel existiert)
im Trigger nur für eine Zeile möglich.
Wie bereits in den anderen Postings gesagt, wurde auf ein
"ordentliches" DB-Design mit GUID-Schlüsseln bewusst verzichtet
(Entwicklungsaufwand, Performance, ...).
Wie Dieter Noeth schon meinte: Nichts ist perse böse.

Ich sehe das nicht als "ordentlicheres" Design an.
Und versuche meist ohne Surrogate auszukommen und ein
Primärschlüssel darf auch gerne mehr Spalten haben,
wo es notwendig ist.
Post by
Dass das eher die Ausnahme ist, hatte ich ja schon geschrieben.
Aber bei einer DB mit gut 150 Tabellen kann diese Ausnahme schon
öfter mal vorkommen.
Das hat mit der Datenbank gar nichts zu tun.
Die Treiber (.NET, ADO/OLEDB, DAO/ODBC) arbeiten mit denen die
Anwendung arbeiten übertragen Änderungen durchweg in einzeiligen
Änderungen.
Schau Dir mal an im SQL Server Profiler an, was da hinter
den Kulissen stattfindet.

Der einzige Fall das man dies über eine Anwendung "hinkriegt"
wäre eine selbstgebaute Anweisung. Und die muss man sich dann
eben verkneifen/umstrukturieren.
Post by
In diesen Fällen soll es halt möglichst effizient zu bewerkstelligen
sein, vor allem ohne dass ich mir dann Gedanken machen muss, dass es
hier anders als nur für einen Datensatz funktioniert.
Die Gedanken sind IMHO aber gerade da wichtig.
Denn evtl. werden einige Hunderttausende Datenzeilen verändert.
Was den Server belastet und schlimmstenfalls durch einen Timeout
auf halber Strecke abgewürgt wird.
Und die Gedanken muss sich da schon der Entwickler machen, denn
der Endanwender weiss darüber wenig bis nichts.

Von einer anderen Warte gesehen:
Das der SQL Server das bis 2000 nicht unterstützt, liegt auch daran,
dass die Microsoft grössere Kunden (mit etwas grösseren Datenbeständen)
diese Funktionalitäten nicht besonders schätzen und benötigen.
Weil es in der Endkonsequenz mehr Schaden als Nutzen bringen kann.
Post by
Post by Elmar Boye
Praktisch würde ich auf das Ändern des Primärschlüssels
eher verzichten.
Schon gerade bei öffentlich zugänglichen, denn die notiert
der eine oder andere auf einem Blatt Papier (und da wird
nie eine Änderung kaskadiert)
Über das Frontend ist das ja für den normalen Nutzer auch nur
datensatzweise möglich. Aber das Erstellen einer SQL-Anweisung "zur
Datenpflege" kann man dann halt für den speziellen Fall als
Dienstleistung anbieten.
Post by Elmar Boye
Und wenns unbedingt sein muss: Besser eine Kopie der
bestehenden Datenzeilen anzulegen und anschliessend
die alten löschen.
Na ja, dass ist vielleicht gar nicht immer so einfach möglich. Eine
Kopie von dem einen Masterdatensatz (der Entitätswert) ist relativ
sinnlos und für die 50.000 Detaildatensätze musst Du dir dann nen
neuen Primärschlüssel überlegen.
Wer muss da überlegen. Ich denke der Benutzer hat da gerade
einen eingegeben?

Gruss
Elmar
2005-09-27 15:04:02 UTC
Permalink
Hallo Elmar!
Post by Elmar Boye
Post by
Post by Elmar Boye
Und wenn Du keinen Primärschlüssel hast, gibt es in SQL
per Definitionem keine Beziehung zwischen zwei Tabellen.
Langes Arbeiten mit Access ISAM Logik lässt das einen
schon mal vergessen ;-).
Primärschlüssel haben wir ja, nur dass das eben auch "änderbare"
Text-Felder sind oder die sich auch mal aus mehreren Feldern
zusammensetzen.
In einer normalisierten Datenbank sollte das normalerweise
nicht vorkommen müssen.
Und eine Artikel/Kundennummer etc. gerade mal ändern
können, ist aus vielerlei Gründen schon abseits der
Datenbank tabu.
Das ist nun mal ein typischer Streitpunkt zwischen Theorie und Praxis. Ich
denke, das brauchen wir hier nicht weiter aufrollen....
Post by Elmar Boye
Post by
In diesen Fällen soll es halt möglichst effizient zu bewerkstelligen
sein, vor allem ohne dass ich mir dann Gedanken machen muss, dass es
hier anders als nur für einen Datensatz funktioniert.
Die Gedanken sind IMHO aber gerade da wichtig.
Denn evtl. werden einige Hunderttausende Datenzeilen verändert.
Was den Server belastet und schlimmstenfalls durch einen Timeout
auf halber Strecke abgewürgt wird.
Und die Gedanken muss sich da schon der Entwickler machen, denn
der Endanwender weiss darüber wenig bis nichts.
Dessen bin ich mir ja bewusst und ich mir mach mir ja genau jetzt Gedanken
drüber, wie ich's am gescheitesten absichern kann.
Post by Elmar Boye
Post by
Post by Elmar Boye
Und wenns unbedingt sein muss: Besser eine Kopie der
bestehenden Datenzeilen anzulegen und anschliessend
die alten löschen.
Na ja, dass ist vielleicht gar nicht immer so einfach möglich. Eine
Kopie von dem einen Masterdatensatz (der Entitätswert) ist relativ
sinnlos und für die 50.000 Detaildatensätze musst Du dir dann nen
neuen Primärschlüssel überlegen.
Wer muss da überlegen. Ich denke der Benutzer hat da gerade
einen eingegeben?
Bleiben wir mal bei dem Beispiel mit Adressgruppen: Über meine
UPDATE-Anweisung würde ich ja nur die paar Gruppen (Masterdatensätze) ändern
(wollen). Aber die ganzen Adressen, die da dranhängen (Detaildatensätze),
haben ja wiederum einen eindeutigen PK (Text). Entweder müsste ich
A. die alten Detaildatensätze zur Sicherung in eine temp. Tabelle kopieren
B. den alten Detaildatensätzen einen anderen PK geben
C. den neuen Detaildatensätzen (mit dem neuen FK) einen anderen PK geben

Mit freundlichen Grüßen
Daniel Barisch
Elmar Boye
2005-09-28 19:00:07 UTC
Permalink
Hallo Daniel,

Daniel Barisch <Daniel Barisch> schrieb ...
Post by
Post by Elmar Boye
Post by
Post by Elmar Boye
Und wenn Du keinen Primärschlüssel hast, gibt es in SQL
per Definitionem keine Beziehung zwischen zwei Tabellen.
Langes Arbeiten mit Access ISAM Logik lässt das einen
schon mal vergessen ;-).
Primärschlüssel haben wir ja, nur dass das eben auch "änderbare"
Text-Felder sind oder die sich auch mal aus mehreren Feldern
zusammensetzen.
In einer normalisierten Datenbank sollte das normalerweise
nicht vorkommen müssen.
Das ist nun mal ein typischer Streitpunkt zwischen Theorie und
Praxis.
Ich bin Praktiker ...
Konkretisiere doch mal Dein Beispiel anhand von zwei, drei Tabellen
wie sie bei euch aussehen und einer Handvoll Testdaten....

Über meine UPDATE-Anweisung würde ich ja nur die paar Gruppen
Post by
(Masterdatensätze) ändern (wollen). Aber die ganzen Adressen,
die da dranhängen (Detaildatensätze), haben ja wiederum einen
eindeutigen PK (Text).
Denn mir scheint Du beisst dich an Dingen wie PK (Text) fest,
was für die Frage von Anfang an ohne grossen Belang war.
Post by
Entweder müsste ich
A. die alten Detaildatensätze zur Sicherung in eine temp. Tabelle
kopieren B. den alten Detaildatensätzen einen anderen PK geben
C. den neuen Detaildatensätzen (mit dem neuen FK) einen anderen PK geben
Dann kann man Dir Beispiele dafür und evtl. auch andere (seltsamere)
Lösungen geben.

Gruss
Elmar
2005-09-29 06:08:14 UTC
Permalink
Hallo Elmar
Post by Elmar Boye
Konkretisiere doch mal Dein Beispiel anhand von zwei, drei Tabellen
wie sie bei euch aussehen und einer Handvoll Testdaten....
Ich dachte eigentlich, so kompliziert zu verstehen ist das nicht mehr,
aber na gut...

Adressgruppen (Name, Einstellung1, Einstellung2, ...):
Nord, Ja, 27
Süd-A, Ja, 33
Süd-B, Nein, 34
Ost, Nein, 0815
West, Nein, 4711

Banken (Name, BLZ, ...)
Dresdner-Bank, 584426754
KSK-Mainz, 468767256
KSK-Freising, 46767359
Dt-Bank-Hamburg, 689265487

Adressen (Name, Ort, GRUPPE, BANK)
mustermann, Mainz, West, KSK-Mainz
kaspers, Dresden, Ost, Dresdner-Bank
kaiser, Hamburg, Nord, Dt-Bank-Hamburg

Jetzt klar? Nehmen wir beispielsweise mal an
A) früher wurde ein DBMS verwendet, dass keine Umlaute konnte. Deshalb gab
es Adressgruppen wie "Sued-...". Die sollten irgendwann gepflegt werden,
weil das neue DBMS (z.B. SQL Server) das nun kann.
B) Alle "Kreisparkassen" werden in "Volkscenter" umbenannt.

Um das am schnellsten zu realisieren würde mir als erstes folgendes
einfallen...
UPDATE Adressgruppen SET Name = Replace(Name, 'Sued', 'Süd)'

Aber genau das geht halt mit unseren jetzigen Triggern schief, weil die nur
genau für einen Datensatz die Änderung an die Adressen weitergeben.
Post by Elmar Boye
Über meine UPDATE-Anweisung würde ich ja nur die paar Gruppen
Post by
(Masterdatensätze) ändern (wollen). Aber die ganzen Adressen,
die da dranhängen (Detaildatensätze), haben ja wiederum einen
eindeutigen PK (Text).
Das macht halt Deinen Vorschlag mit dem Kopieren (Sichern) der Datensätze
etwas komplizierter.
Post by Elmar Boye
Denn mir scheint Du beisst dich an Dingen wie PK (Text) fest,
was für die Frage von Anfang an ohne grossen Belang war.
Doch, genau das hat Belang! Denn in unseren Tabellen gibt es eigentlich nur
drei Typen von PK's
1) Autowert-Integer, für die das Problem nicht gilt, weil die nicht
umbenannt werden
2) Text-Felder mit i.d.R. 20-50 Zeichen, die genau das Problem hervorrufen.
3) PK's aus mehrern Text-Feldern (bisher max. zwei), die nach unserem
(damaligen) Wissen eine Lösung über Beziehungen ausgeschlossen haben, weil
man da nur jeweils ein Feld verwenden konnte.
Post by Elmar Boye
Dann kann man Dir Beispiele dafür und evtl. auch andere (seltsamere)
Lösungen geben.
Na da bin ich mal gespannt....


Mit freundlichen Grüßen
Daniel Barisch
Jürgen Volke
2005-09-29 07:02:33 UTC
Permalink
Hallo Daniel
Post by
Post by Elmar Boye
Konkretisiere doch mal Dein Beispiel anhand von zwei, drei Tabellen
wie sie bei euch aussehen und einer Handvoll Testdaten....
Ich dachte eigentlich, so kompliziert zu verstehen ist das nicht mehr,
aber na gut...
Nord, Ja, 27
Süd-A, Ja, 33
Süd-B, Nein, 34
Ost, Nein, 0815
West, Nein, 4711
Banken (Name, BLZ, ...)
Dresdner-Bank, 584426754
KSK-Mainz, 468767256
KSK-Freising, 46767359
Dt-Bank-Hamburg, 689265487
Adressen (Name, Ort, GRUPPE, BANK)
mustermann, Mainz, West, KSK-Mainz
kaspers, Dresden, Ost, Dresdner-Bank
kaiser, Hamburg, Nord, Dt-Bank-Hamburg
Jetzt klar? Nehmen wir beispielsweise mal an
A) früher wurde ein DBMS verwendet, dass keine Umlaute konnte.
Deshalb gab es Adressgruppen wie "Sued-...". Die sollten irgendwann
gepflegt werden, weil das neue DBMS (z.B. SQL Server) das nun kann.
B) Alle "Kreisparkassen" werden in "Volkscenter" umbenannt.
Um das am schnellsten zu realisieren würde mir als erstes folgendes
einfallen...
UPDATE Adressgruppen SET Name = Replace(Name, 'Sued', 'Süd)'
MZ sag doch bitte mal was dazu!

Ich finde das ist falsches Datenbank-Design und sollte hier eigentlich gar nicht
zur Diskussion gestellt werden.

Gruß Jürgen
2005-09-29 07:45:55 UTC
Permalink
Hallo Jürgen!
Post by Jürgen Volke
MZ sag doch bitte mal was dazu!
Darf ich erfahren wer MZ ist?
Post by Jürgen Volke
Ich finde das ist falsches Datenbank-Design und sollte hier eigentlich gar
nicht zur Diskussion gestellt werden.
Dazu hatte ich mich bereits geäußert...
Post by Jürgen Volke
Das ist nun mal ein typischer Streitpunkt zwischen Theorie und Praxis. Ich
denke, das brauchen wir hier nicht weiter aufrollen....
Das Design habe ich ja gar nicht zur Diskussion gestellt. Mir ist vollkommen
klar, dass das für die Theoretiker unter euch so nicht in Ordnung ist. Aber
es ist nun mal so und ich muss damit leben.


Mit freundlichen Grüßen
Daniel Barisch
Jürgen Volke
2005-09-29 08:26:27 UTC
Permalink
Hallo Daniel
Post by
Post by Jürgen Volke
MZ sag doch bitte mal was dazu!
Darf ich erfahren wer MZ ist?
Michael Zimmermann aus Mainz
Post by
Post by Jürgen Volke
Ich finde das ist falsches Datenbank-Design und sollte hier
eigentlich gar nicht zur Diskussion gestellt werden.
Dazu hatte ich mich bereits geäußert...
Post by Jürgen Volke
Das ist nun mal ein typischer Streitpunkt zwischen Theorie und
Praxis. Ich denke, das brauchen wir hier nicht weiter aufrollen....
Das Design habe ich ja gar nicht zur Diskussion gestellt. Mir ist
vollkommen klar, dass das für die Theoretiker unter euch so nicht in
Ordnung ist. Aber es ist nun mal so und ich muss damit leben.
das tut mir jetzt wirklich leid.
und der Verantwortliche ist nicht mehr zur Rechenschaft zu ziehen?

Gruß Jürgen
2005-09-29 08:44:07 UTC
Permalink
Hallo Jürgen!
Post by Jürgen Volke
Post by
Post by Jürgen Volke
MZ sag doch bitte mal was dazu!
Darf ich erfahren wer MZ ist?
Michael Zimmermann aus Mainz
Mmh, das scheint wohl der HKW für die SQL Server - Gruppe zu sein...
Post by Jürgen Volke
das tut mir jetzt wirklich leid.
und der Verantwortliche ist nicht mehr zur Rechenschaft zu ziehen?
Wenn Du Dich mit einem Unternehmen anlegen willst, dessen Software von
inzwischen rund 25.000 Anwendern eingesetzt wird (Nicht wir, sondern das
Fremdsystem, in das wir uns einklinken), dann bitte...

Mit freundlichen Grüßen
Daniel Barisch
Elmar Boye
2005-09-29 09:26:08 UTC
Permalink
HalloDaniel,

Daniel Barisch <Daniel Barisch> schrieb ...
Post by
Post by Elmar Boye
Konkretisiere doch mal Dein Beispiel anhand von zwei, drei Tabellen
wie sie bei euch aussehen und einer Handvoll Testdaten....
Ich dachte eigentlich, so kompliziert zu verstehen ist das nicht mehr,
aber na gut...
Mein Eindruck war - und wurde schon wieder bestätigt - das die
Verständnisprobleme eher auf Deiner Seite liegen.

So wollte ich das sehen - wobei das nun das Erstellen die Zeit
für einige Variationen zum Thema aufgefressen hat...

USE tempdb
GO
SET NOCOUNT ON
GO

--DROP TABLE dbo.Adressen, dbo.Banken, dbo.Adressgruppen
GO

CREATE TABLE dbo.Adressgruppen (
Name varchar(30) NOT NULL,
Einstellung1 varchar(4) NOT NULL
CONSTRAINT DF_Adressgruppen_Einstellung1 DEFAULT('Nein'),
CONSTRAINT CK_Adressgruppen_Einstellung1 CHECK (Einstellung1 IN ('Ja', 'Nein')),

Einstellung2 varchar(10) NOT NULL,

CONSTRAINT PK_Adressgruppen PRIMARY KEY (Name))
GO


CREATE TABLE dbo.Banken (
Name varchar(30) NOT NULL,
BLZ int NOT NULL,

CONSTRAINT PK_Banken PRIMARY KEY (Name))
GO

CREATE TABLE dbo.Adressen (
Name varchar(30) NOT NULL,
Ort varchar(30) NOT NULL,
Gruppe varchar(30) NULL,
Bank varchar(30) NULL

CONSTRAINT PK_Adress PRIMARY KEY (Name),

CONSTRAINT FK_Adressen_Adressgruppen
FOREIGN KEY (Gruppe)
REFERENCES dbo.Adressgruppen (Name)
ON UPDATE CASCADE,

CONSTRAINT FK_Adressen_Banken
FOREIGN KEY (Bank)
REFERENCES dbo.Banken (Name)
ON UPDATE CASCADE)
GO

INSERT INTO dbo.Adressgruppen VALUES('Nord', 'Ja', '27')
INSERT INTO dbo.Adressgruppen VALUES('Sued-A', 'Ja', '33')
INSERT INTO dbo.Adressgruppen VALUES('Sued-B', 'Nein', '34')
INSERT INTO dbo.Adressgruppen VALUES('Ost', 'Nein', '0815')
INSERT INTO dbo.Adressgruppen VALUES('West', 'Nein', '4711')
GO

INSERT INTO dbo.Banken VALUES('Dresdner-Bank', 584426754)
INSERT INTO dbo.Banken VALUES('KSK-Mainz', 468767256)
INSERT INTO dbo.Banken VALUES('KSK-Freising', 46767359)
INSERT INTO dbo.Banken VALUES('Dt-Bank-Hamburg', 689265487)
GO

INSERT INTO dbo.Adressen VALUES('Mustermann', 'Mainz', 'West', 'KSK-Mainz')
INSERT INTO dbo.Adressen VALUES('Kaspers', 'Dresden', 'Ost', 'Dresdner-Bank')
INSERT INTO dbo.Adressen VALUES('Kaiser', 'Hamburg', 'Nord', 'Dt-Bank-Hamburg')
INSERT INTO dbo.Adressen VALUES('Maier', 'München', 'Sued-A', 'KSK-Freising')
INSERT INTO dbo.Adressen VALUES('Mayer', 'Freising', 'Sued-B', 'KSK-Freising')
GO
Post by
A) früher wurde ein DBMS verwendet, dass keine Umlaute konnte.
Deshalb gab es Adressgruppen wie "Sued-...". Die sollten irgendwann
gepflegt werden, weil das neue DBMS (z.B. SQL Server) das nun kann.
B) Alle "Kreisparkassen" werden in "Volkscenter" umbenannt.
Ich könnte jetzt anführen, dass obige Struktur schnell Probleme
mit unterschiedlichen Zeichensätze (Stichwort Sortierfolgen)
bekommt, aber das gehört ja wohl bei Dir schon wieder zur Theorie.
Post by
Um das am schnellsten zu realisieren würde mir als erstes folgendes
einfallen...
UPDATE Adressgruppen SET Name = Replace(Name, 'Sued', 'Süd)'
Und das heisst dann: Wo ist da ein Problem...

UPDATE dbo.Adressgruppen SET Name = Replace(Name, 'Sued', 'Süd')
-- wir gehen stillschweigend von genügend Platz aus
UPDATE dbo.Banken SET Name = Replace(Name, 'KSK-', 'Volkcenter ')

SELECT * FROM dbo.Adressen
GO
Post by
Aber genau das geht halt mit unseren jetzigen Triggern schief, weil
die nur genau für einen Datensatz die Änderung an die Adressen
weitergeben.
Mit Triggern gehts genauso... kommt bei Bedarf aber frühstens
heute nachmittag...

Ja und ich weiss, dass es bei zirkulären Beziehungen so nicht
mehr geht, nur das gibt das Dein Beispiel nicht her.
Aber vielleicht will ja noch jemand anders mit den Testdaten
spielen...
Post by
Post by Elmar Boye
Über meine UPDATE-Anweisung würde ich ja nur die paar Gruppen
Post by
(Masterdatensätze) ändern (wollen). Aber die ganzen Adressen,
die da dranhängen (Detaildatensätze), haben ja wiederum einen
eindeutigen PK (Text).
Das macht halt Deinen Vorschlag mit dem Kopieren (Sichern) der
Datensätze etwas komplizierter.
Na und? Ich denke, Du bist ein Entwickler, das sind endlich
mal Herausforderungen ;-)
Post by
Post by Elmar Boye
Denn mir scheint Du beisst dich an Dingen wie PK (Text) fest,
was für die Frage von Anfang an ohne grossen Belang war.
Doch, genau das hat Belang!
3) PK's aus mehrern Text-Feldern (bisher max. zwei), die
Post by
nach unserem (damaligen) Wissen eine Lösung über Beziehungen
ausgeschlossen haben, weil man da nur jeweils ein Feld verwenden
konnte.
Damit das mit (damaligen) nicht immer passiert empfehle ich
etwas mehr Lektüre... Dann musst Du nicht immer alles als
Theoretie abqualifizieren, sondern kannst dieselbe in Praxis
anwenden. Auch wenn zugrundeliegende Strukturen vermurkst sind
und da herum werkeln muss.

Gruss
Elmar
2005-09-29 10:11:34 UTC
Permalink
Hallo Elmar!

Gleich mal vorneweg.... Ich möchte hier niemandem auf den Schlips treten
oder so. Ich bin recht neu auf dem Gebiet SQL Server, da bisher eine
Jet-Datenbank unter dem System lag. Ich muss eben nun nur aus mehr oder
weniger rein wirtschaftlicher Sicht schnellstmöglich zum nötigen Wissen
gelangen. Ich leugne also gar nicht, dass da noch die eine oder andere
Lektüre notwendig ist. Falls ich doch irgendwo das Gegenteil behauptet haben
sollte, dann war das nicht meine Absicht!
Post by Elmar Boye
Post by
Post by Elmar Boye
Konkretisiere doch mal Dein Beispiel anhand von zwei, drei Tabellen
wie sie bei euch aussehen und einer Handvoll Testdaten....
Ich dachte eigentlich, so kompliziert zu verstehen ist das nicht mehr,
aber na gut...
Mein Eindruck war - und wurde schon wieder bestätigt - das die
Verständnisprobleme eher auf Deiner Seite liegen.
Mit "nicht mehr kompliziert" meinte ich lediglich die "typischen"
Datenstrukturen unserer DB (Adressgruppen - Adressen), nicht jedoch das
eigentliche Problem. Sorry, wenn das falsch rübergekommen ist.
Post by Elmar Boye
Post by
A) früher wurde ein DBMS verwendet, dass keine Umlaute konnte.
Deshalb gab es Adressgruppen wie "Sued-...". Die sollten irgendwann
gepflegt werden, weil das neue DBMS (z.B. SQL Server) das nun kann.
B) Alle "Kreisparkassen" werden in "Volkscenter" umbenannt.
Ich könnte jetzt anführen, dass obige Struktur schnell Probleme
mit unterschiedlichen Zeichensätze (Stichwort Sortierfolgen)
bekommt, aber das gehört ja wohl bei Dir schon wieder zur Theorie.
Ich will hier sicher nicht alles als "Theorie" abtun! Zum einen, weil die DB
nicht auf meinem Mist gewachsen ist, zum anderen (im speziellen Fall der
Text-PK's) aber auch, weil ich GUID-Schlüssel einfach nicht für
sinnvoll/erforderlich halte, wenn durch das DBMS die ref. Integrität
sichergestellt werden kann (an dieser Stelle mal abstrahiert von der
tatsächlichen Umsetzung).
Post by Elmar Boye
Post by
Um das am schnellsten zu realisieren würde mir als erstes folgendes
einfallen...
UPDATE Adressgruppen SET Name = Replace(Name, 'Sued', 'Süd)'
Und das heisst dann: Wo ist da ein Problem...
UPDATE dbo.Adressgruppen SET Name = Replace(Name, 'Sued', 'Süd')
-- wir gehen stillschweigend von genügend Platz aus
UPDATE dbo.Banken SET Name = Replace(Name, 'KSK-', 'Volkcenter ')
SELECT * FROM dbo.Adressen
GO
Dann habe ich Adressen, wo immer noch die alte Gruppe/Bank drin steht, weil
unsere (AFTER-) UPDATE-Trigger im jetzigen Stand nur den PK-Wert des letzten
Datensatzes aus der inserted und deleted Tabelle auslesen und mit diesen die
Aktualisierungsweitergabe durchführen. Wird jeweils nur ein Datensatz
geändert, dann steht in diesen temp. Tabellen ja auch jeweils nur ein
Datensatz drin. Werden mehrere Datensätze geänderten dann erwische ich mehr
oder weniger zufällig zwei PK-Werte, die (wie ich gelernt habe), streng
genommen nicht mal zusammenpassen müssen (alt -> neu).
Post by Elmar Boye
Mit Triggern gehts genauso... kommt bei Bedarf aber frühstens
heute nachmittag...
Na genau das ist doch meine Frage. Ich sehe bisher keine Möglichkeit, einen
eindeutigen Zusammenhang zwischen den einzelnen Datensätzen in
Detail-Daten-, inserted- und deleted-Tabelle herzustellen, so dass ich
Datensätze mit dem alten Wert (aus deletetd) in der Detail-Datentabelle
selektieren und mit dem neuen Wert (aus inserted) aktualisieren könnte.
Post by Elmar Boye
Ja und ich weiss, dass es bei zirkulären Beziehungen so nicht
mehr geht, nur das gibt das Dein Beispiel nicht her.
Zirkuläre Bezüge kommen bei uns nicht vor.
Post by Elmar Boye
Post by
Post by Elmar Boye
Über meine UPDATE-Anweisung würde ich ja nur die paar Gruppen
Post by
(Masterdatensätze) ändern (wollen). Aber die ganzen Adressen,
die da dranhängen (Detaildatensätze), haben ja wiederum einen
eindeutigen PK (Text).
Das macht halt Deinen Vorschlag mit dem Kopieren (Sichern) der
Datensätze etwas komplizierter.
Na und? Ich denke, Du bist ein Entwickler, das sind endlich
mal Herausforderungen ;-)
Herausforderungen die ich aus technischer Sicht sehr gern annehmen würde,
aber aus wirtschaftlicher (Zeit/Kosten) und praktischer (Fremdsystem!) Sicht
nicht angehen kann.
Post by Elmar Boye
Damit das mit (damaligen) nicht immer passiert empfehle ich
etwas mehr Lektüre... Dann musst Du nicht immer alles als
Theoretie abqualifizieren, sondern kannst dieselbe in Praxis
anwenden. Auch wenn zugrundeliegende Strukturen vermurkst sind
und da herum werkeln muss.
Da bin ich ja gerade dabei, aber es geht nun mal nicht alles auf einmal.
Und ihr helft mir nunmal immer so nett, das verwöhnt...


Mit freundlichen Grüßen
Daniel Barisch
Stefan Hoffmann
2005-09-29 10:36:21 UTC
Permalink
tach Daniel,
Post by
Gleich mal vorneweg.... Ich möchte hier niemandem auf den Schlips treten
oder so. Ich bin recht neu auf dem Gebiet SQL Server, da bisher eine
Jet-Datenbank unter dem System lag.
Ihr portiert eine .mdb auf den SQL Server?


mfG
--> stefan <--
--
Access-FAQ http://www.donkarl.com/
KnowHow.mdb http://www.freeaccess.de
MSSQL-FAQ http://www.berndjungbluth.de
Newbie-Info http://www.doerbandt.de/Access/Newbie.htm
2005-09-29 10:54:24 UTC
Permalink
Hallo Stefan!
Post by Stefan Hoffmann
Ihr portiert eine .mdb auf den SQL Server?
Na ja fast. Genauer gesagt portieren wir die Anwengung, die bisher auf eine
Jet-Datenbank zugegriffen hat für den Zugriff auf eine SQL-Datenbank.


Mit freundlichen Grüßen
Daniel Barisch
Stefan Hoffmann
2005-09-29 11:24:50 UTC
Permalink
tach Daniel,
Post by
Post by Stefan Hoffmann
Ihr portiert eine .mdb auf den SQL Server?
Na ja fast. Genauer gesagt portieren wir die Anwengung, die bisher auf eine
Jet-Datenbank zugegriffen hat für den Zugriff auf eine SQL-Datenbank.
Verpasst den allen Tabellen eine IDENTITY Spalte, muß nicht PK sein.
Dann ist das Problem gelöst.
Alternativ kann ich mir auch einen Abgleich der Daten mittels TIMESTAMP
vorstellen.


mfG
--> stefan <--
--
Access-FAQ http://www.donkarl.com/
KnowHow.mdb http://www.freeaccess.de
MSSQL-FAQ http://www.berndjungbluth.de
Newbie-Info http://www.doerbandt.de/Access/Newbie.htm
2005-09-29 13:02:19 UTC
Permalink
Hallo Stefan!
Post by
Post by Stefan Hoffmann
Ihr portiert eine .mdb auf den SQL Server?
Na ja fast. Genauer gesagt portieren wir die Anwengung, die bisher auf
eine Jet-Datenbank zugegriffen hat für den Zugriff auf eine
SQL-Datenbank.
Verpasst den allen Tabellen eine IDENTITY Spalte, muß nicht PK sein. Dann
ist das Problem gelöst.
Wenn ich Deinen Gedankengang jetzt richtig verstehe, dann DARF die
IDENTITY-Spalte nicht der PK sein. Dann könnte ich nämlich eine Zuordnung
zwischen den Datensätzen aus der deleted- und der inserted-Tabelle
herstellen, somit die richtigen Datensätze mit dem alten PK-Wert auswählen
und den neuen eintragen ...

Bin ich auf dem richtigen Weg?


Mit freundlichen Grüßen
Daniel Barisch
Stefan Hoffmann
2005-09-29 14:15:38 UTC
Permalink
tach Daniel,
Post by
Post by
Na ja fast. Genauer gesagt portieren wir die Anwengung, die bisher auf
eine Jet-Datenbank zugegriffen hat für den Zugriff auf eine
SQL-Datenbank.
Verpasst den allen Tabellen eine IDENTITY Spalte, muß nicht PK sein. Dann
ist das Problem gelöst.
Wenn ich Deinen Gedankengang jetzt richtig verstehe, dann DARF die
IDENTITY-Spalte nicht der PK sein.
Wenn sie nicht PK ist, könnt ihr eure alten PKs erhalten.
Post by
Dann könnte ich nämlich eine Zuordnung
zwischen den Datensätzen aus der deleted- und der inserted-Tabelle
herstellen, somit die richtigen Datensätze mit dem alten PK-Wert auswählen
und den neuen eintragen ...
Bin ich auf dem richtigen Weg?
JA.


mfG
--> stefan <--
--
Access-FAQ http://www.donkarl.com/
KnowHow.mdb http://www.freeaccess.de
MSSQL-FAQ http://www.berndjungbluth.de
Newbie-Info http://www.doerbandt.de/Access/Newbie.htm
Dieter Liessmann
2005-09-29 11:16:17 UTC
Permalink
Jetz muss ich auch noch meinen Senf dazu geben..

Daniel Barisch schrieb:
<snip>
Post by
Dann habe ich Adressen, wo immer noch die alte Gruppe/Bank drin
steht, weil unsere (AFTER-) UPDATE-Trigger im jetzigen Stand nur den
PK-Wert des letzten Datensatzes aus der inserted und deleted Tabelle
auslesen und mit diesen die Aktualisierungsweitergabe durchführen.
Wird jeweils nur ein Datensatz geändert, dann steht in diesen temp.
Tabellen ja auch jeweils nur ein Datensatz drin. Werden mehrere
Datensätze geänderten dann erwische ich mehr oder weniger zufällig
zwei PK-Werte, die (wie ich gelernt habe), streng genommen nicht mal
zusammenpassen müssen (alt -> neu).
Nimm doch bitte einfach mal Elmars Code und lass ihn über den QueryAnalyzer
auf denen SQL-Server los.
Ändere dann in den Adressgruppen Sued in Süd.
Siehe da..
Auch in Adressen ist alles geändert, ganz ohne Trigger.
Einfach die richtige Beziehung definiert und schon geht's.
siehe:
CONSTRAINT FK_Adressen_Adressgruppen
FOREIGN KEY (Gruppe)
REFERENCES dbo.Adressgruppen (Name)
ON UPDATE CASCADE,


Also muss ich Elmars frage wiederholen:
Wo is das Problem???
--
So long Dieter
2005-09-29 13:02:24 UTC
Permalink
Hallo Dieter!
Post by Dieter Liessmann
Nimm doch bitte einfach mal Elmars Code und lass ihn über den
QueryAnalyzer auf denen SQL-Server los.
Ändere dann in den Adressgruppen Sued in Süd.
Siehe da..
Auch in Adressen ist alles geändert, ganz ohne Trigger.
Ich hab ja auch nicht gesagt, dass Elmars Code nicht funktioniert.
Post by Dieter Liessmann
Einfach die richtige Beziehung definiert und schon geht's.
Wo is das Problem???
Hast Du Dir den ganzen Thread durchgelesen?

Dann wüsstest Du, dass wir ohne Beziehungen arbeiten, weil <angeblich> im
SQL Server nur über ein Feld möglich sind. Wir haben in der Datenbank aber
auch Fälle, wo die Beziehung über zwei Felder gehen müsste. Deshalb haben
wir uns für Trigger entschieden, weil so für den einfachen Fall (ein
Datensatz) die Aktualisierungsweitergabe recht einfach realisierbar ist. Nur
funktionieren die halt nicht, wenn mehrere PK's auf einmal geändert werden.
Ich komm ja leider nicht dazu, die Aussage bzgl. der Beziehungen zu
prüfen....


Mit freundlichen Grüßen
Daniel Barisch
Dieter Liessmann
2005-09-30 08:16:09 UTC
Permalink
Hi Daniel,
Post by
Hallo Dieter!
Post by Dieter Liessmann
Nimm doch bitte einfach mal Elmars Code und lass ihn über den
QueryAnalyzer auf denen SQL-Server los.
Ändere dann in den Adressgruppen Sued in Süd.
Siehe da..
Auch in Adressen ist alles geändert, ganz ohne Trigger.
Ich hab ja auch nicht gesagt, dass Elmars Code nicht funktioniert.
Post by Dieter Liessmann
Einfach die richtige Beziehung definiert und schon geht's.
Wo is das Problem???
Hast Du Dir den ganzen Thread durchgelesen?
Na klar.
Post by
Dann wüsstest Du, dass wir ohne Beziehungen arbeiten, weil
<angeblich> im SQL Server nur über ein Feld möglich sind.
Das hat dein Beispiel leider nicht hergegeben. Da Du das Beispiel gewählt
hast bin ich davon ausgegangen, dass Du aus diesem einfachen Beispiel auf
dein etwas komplexeres schließen kannst.
Klar kann man Beziehungen auch über mehrere Felder definieren.
Post by
Wir haben
in der Datenbank aber auch Fälle, wo die Beziehung über zwei Felder
gehen müsste. Deshalb haben wir uns für Trigger entschieden, weil so
für den einfachen Fall (ein Datensatz) die Aktualisierungsweitergabe
recht einfach realisierbar ist. Nur funktionieren die halt nicht,
wenn mehrere PK's auf einmal geändert werden. Ich komm ja leider
nicht dazu, die Aussage bzgl. der Beziehungen zu prüfen....
Kannst Du mit einem Aufwand von ca. 5 Minuten an dem Beispiel von Elmar
prüfen.

Soweit die direkten Antworten. Nun noch etwas allgemeinere Betrachtungen.
Deine eigenen Aussagen waren etwas gegensätzlich, so dass es schwierig ist
dir "auf den Punkt" zu helfen.
Erst erweckst Du den Eindruck, dass Du an dem Backend nichts ändern kannst,
dann räumst Du das aber doch ein.

Du kannst "problemlos" Änderungen am Backend vornehmen obwohl schon 1000ende
von Kunden damit arbeiten.
Alle Änderungen lassen sich durch SQL-Statements automatisieren. Du musst
also bei deinen Kunden nur ein Skript laufen lassen.

Beziehungen über mehrere Felder würde ich nur in Ausnahmesituationen
anwenden, da Sie gerade mit UPDATE CASCADE zu Performance-Problemen führen
können. Auch das Handling (gerade von Triggern) ist einfacher, wenn Du in
einem solchen Fall in deiner Mastertabelle eine Identitätsspalte einbaust
und die Beziehung darüber herstellst. Ausserdem fällt mir im Moment auch
kein praktisches Beispiel ein in dem sauber normalisiert wurde und eine
Beziehung über mehrere Felder nötig ist (kann aber auch an meiner mangelnden
Phantasie liegen ;-)).

Ich würde sicherlich keine Identitätsspalte zusätzlich in meine Tabelle
bauen die zwar Unique aber nicht PK ist (wie von Stefan vorgeschlagen)! Wenn
ich die Datenstruktur schön verändere, dann verbessere ich sie und mach sie
nicht noch schlimmer.

Wenn jemand so nett ist und Dir ein komplettes Skript als Beispiel liefert,
dass Du nur per Copy and Paste ausprobieren kannst, solltest Du so nett sein
dies wenigstens mal auszuprobieren. Dann tritt auch sehr schnell ein
Lerneffect ein.

Ich bin mal so frei und vergreif mich an Elmars Beispiel:

USE tempdb
GO
SET NOCOUNT ON
GO

--DROP TABLE dbo.Adressen, dbo.Adressgruppen
GO

CREATE TABLE dbo.Adressgruppen (
Name1 varchar(30) NOT NULL,
Name2 varchar(30) NOT NULL,
Einstellung1 varchar(4) NOT NULL
CONSTRAINT DF_Adressgruppen_Einstellung1 DEFAULT('Nein'),
CONSTRAINT CK_Adressgruppen_Einstellung1 CHECK (Einstellung1 IN ('Ja',
'Nein')),

Einstellung2 varchar(10) NOT NULL,

CONSTRAINT PK_Adressgruppen PRIMARY KEY (Name1, Name2))
GO

CREATE TABLE dbo.Adressen (
Name varchar(30) NOT NULL,
Ort varchar(30) NOT NULL,
Gruppe1 varchar(30) NULL,
Gruppe2 varchar(30) NULL,
Bank varchar(30) NULL

CONSTRAINT PK_Adress PRIMARY KEY (Name),

CONSTRAINT FK_Adressen_Adressgruppen
FOREIGN KEY (Gruppe1, Gruppe2)
REFERENCES dbo.Adressgruppen (Name1, Name2)
ON UPDATE CASCADE)
GO

INSERT INTO dbo.Adressgruppen VALUES('Nord', 'A', 'Ja', '27')
INSERT INTO dbo.Adressgruppen VALUES('Sued', 'A', 'Ja', '33')
INSERT INTO dbo.Adressgruppen VALUES('Sued', 'B', 'Nein', '34')
INSERT INTO dbo.Adressgruppen VALUES('Ost', 'A', 'Nein', '0815')
INSERT INTO dbo.Adressgruppen VALUES('West', 'A', 'Nein', '4711')
GO


INSERT INTO dbo.Adressen VALUES('Mustermann', 'Mainz', 'West', 'A',
'KSK-Mainz')
INSERT INTO dbo.Adressen VALUES('Kaspers', 'Dresden', 'Ost', 'A',
'Dresdner-Bank')
INSERT INTO dbo.Adressen VALUES('Kaiser', 'Hamburg', 'Nord', 'A',
'Dt-Bank-Hamburg')
INSERT INTO dbo.Adressen VALUES('Maier', 'München', 'Sued', 'A',
'KSK-Freising')
INSERT INTO dbo.Adressen VALUES('Mayer', 'Freising', 'Sued', 'B',
'KSK-Freising')
GO


Und dann schau Dir mal an was mit
UPDATE dbo.Adressgruppen SET Name1 = Replace(Name1, 'Sued', 'Süd')
passiert.
--
So long Dieter
2005-09-30 12:01:28 UTC
Permalink
Hallo Dieter!
Post by Dieter Liessmann
Post by
Dann wüsstest Du, dass wir ohne Beziehungen arbeiten, weil
<angeblich> im SQL Server nur über ein Feld möglich sind.
Das hat dein Beispiel leider nicht hergegeben. Da Du das Beispiel gewählt
hast bin ich davon ausgegangen, dass Du aus diesem einfachen Beispiel auf
dein etwas komplexeres schließen kannst.
Das Beispiel, welches ich angeführt hatte, stellte lediglich die Strukturen
in unserer Datenbank dar, die eine Aktualisierungsweitergabe über Trigger
verhindern, wenn ein Update über mehrere Datensätze ausgeführt wird.
Das wir uns überhaupt für Trigger statt Beziehungen entschieden hatten, lag
nicht in diesen Strukturen begründet, sondern eben ... siehe nächster
Abschnitt. Dass die aufgeführten Strukturbeispiele das nicht hergegeben
haben, ist (war) mir klar, aber ich war halt davon ausgegangen, dass Elmar
noch nicht verstanden hatte, wie ich das mit den Fremdschlüsseln meinte
(eben die aufgeführten Strukturbeispiele).
Post by Dieter Liessmann
Klar kann man Beziehungen auch über mehrere Felder definieren.
Ok, hier muss ich mich erstmal selbst bissl verhauen, da ich das Problem mit
den Beziehungen zwar zwar nicht völlig aber zumindest etwas anders im
Hinterkopf hatte.
Also ... Deshalb jetzt die Strukturen, die eine Lösung über Beziehungen aus
unserer (damaligen) Sicht ausgeschlossen haben:

Angenommen es gibt eine Adressen-Tabelle (wie ich sie bereits aufgeführt
hatte) und eine Tabelle mit Objekten (Häuser, installierte Heizungen oder
derartiges). Einem Datensatz aus der Tabelle Objekte können in
unterschiedlichen Feldern mehrere Adressen zugeordnet sein, z.B. eine für
den Standort des Objektes, eine für den Rechnungempfänger und eine für die
verantwortliche Instandsetzungsfirma. Diese drei Adressen eines Objektes
haben untereinander nicht wirklich etwas mit einander zu tun, deshalb müsste
ich quasi drei Beziehungen zwischen den zwei Tabellen definieren und da
knallt's schon bei der zweiten....

Das Einführen der FOREIGN KEY-Einschränkung 'FK_Tab1_Tab2_2' für die
Tab2-Tabelle kann Schleifen oder mehrere kaskadierende Pfade verursachen.
Geben SIE ON DELETE NO ACTION oder ON UPDATE NO ACTION an,
oder ändern Sie andere FOREIGN KEY-Einschränkungen.

Man kann aber für keine der Beziehungen das Update weglassen, da das doch
wieder inkonsistente Zustände zur Folge hätte.

UND: Ich weiß, dass man das eigentlich auf mehrere Tabellen auftrennen
(normalisieren) müsste und es dann wieder gehen würde.

zu
Post by Dieter Liessmann
Kannst Du mit einem Aufwand von ca. 5 Minuten an dem Beispiel von Elmar
prüfen.
und
Post by Dieter Liessmann
Wenn jemand so nett ist und Dir ein komplettes Skript als Beispiel
liefert, dass Du nur per Copy and Paste ausprobieren kannst, solltest Du
so nett sein dies wenigstens mal auszuprobieren. Dann tritt auch sehr
schnell ein Lerneffect ein.
Post by
Ich hab ja auch nicht gesagt, dass Elmars Code nicht funktioniert.
Genauer:
Ich war mir sicher, dass Elmars Code funktioniert und konnte mir auch
vorstellen wie, ohne das wirklich auszuprobieren. Allerdings deckte es eben
das o.g. Problem nicht ab, da er immer nur eine Beziehung zwischen zwei
Tabellen hatte (weil ich dieses Strukturbeispiel nicht aufgeführt hatte).
Post by Dieter Liessmann
Soweit die direkten Antworten. Nun noch etwas allgemeinere Betrachtungen.
Deine eigenen Aussagen waren etwas gegensätzlich, so dass es schwierig ist
dir "auf den Punkt" zu helfen.
Ich weiß, aber es ist halt schwer die tatsächliche Situation genauer zu
beschreiben, dabei aber "anonym" zu bleiben.
Post by Dieter Liessmann
Erst erweckst Du den Eindruck, dass Du an dem Backend nichts ändern
kannst, dann räumst Du das aber doch ein.
Klingt sicher blöd aber genauso ist es. Es wird in Zukunft Fälle geben, wo
wir das können (könnten) und Fälle wo nicht. Wir streben aber lieber eine
Lösung an, die für beide (und eventuell in Zukunft weiteren) Fälle
gleichermaßen umsetzbar ist. Ich will das aber hier nicht noch weiter
ausbauen, ich denke der Thread ist schon lang genug. Bitte nehmt es einfach
so hin, dass ich nur einen Workaround für eine bereits vermurkste
Datenstruktur gesucht habe.
Post by Dieter Liessmann
Du kannst "problemlos" Änderungen am Backend vornehmen obwohl schon
1000ende von Kunden damit arbeiten.
Nur wenn es "Dein" Backend ist. Ansonsten bekommt der Kunde Probleme mit der
anderen Software.
Post by Dieter Liessmann
Alle Änderungen lassen sich durch SQL-Statements automatisieren. Du musst
also bei deinen Kunden nur ein Skript laufen lassen.
Das wir die Datenbank nach Belieben umgestalten könnten, weiß ich. Aber wir
können leider die Fremdsoftware nicht so umprogrammieren, dass sie mit
unserer Vorstellung der Datenbank funktioniert.
Post by Dieter Liessmann
können. Auch das Handling (gerade von Triggern) ist einfacher, wenn Du in
einem solchen Fall in deiner Mastertabelle eine Identitätsspalte einbaust
und die Beziehung darüber herstellst.
Das geht ja in die Richtung, die Stefan vorgeschlagen hatte und wenn ich
ihn richtig verstanden habe bräuchte ich dann nicht mal eine Beziehung zu
den Detailtabellen, sondern könnte dann in den Triggern "manuell" eine
Zuordnung zwischen inserted- und deleted-Tabelle herstellen und die
entsprechend weitergeben.
Post by Dieter Liessmann
Ausserdem fällt mir im Moment auch kein praktisches Beispiel ein in dem
sauber normalisiert wurde und eine Beziehung über mehrere Felder nötig ist
(kann aber auch an meiner mangelnden Phantasie liegen ;-)).
Es ist ja nicht sauber normalisert, hab ich doch schon mehrfach zugegeben.
Und warum das nicht so einfach ist auch.
Post by Dieter Liessmann
USE tempdb
[...]
Hab mir diesmal die "Mühe" gemacht und es ausprobiert und es hat
funktioniert. Hatte ich aber auch nicht anders erwartet. Es deckt nur leider
das Problem der mehrfachen Beziehung zwischen zwei Tabellen nicht ab.
Sorry, dass ich das bisher nicht eher etwas besser beschrieben hatte,
aber ich hab "den Verantwortlichen" erst heute mal wieder zu fassen
bekommen.


Mit freundlichen Grüßen
Daniel Barisch
Jürgen Volke
2005-09-30 12:17:50 UTC
Permalink
Hallo Daniel
Post by
Angenommen es gibt eine Adressen-Tabelle (wie ich sie bereits
aufgeführt hatte) und eine Tabelle mit Objekten (Häuser, installierte
Heizungen oder derartiges). Einem Datensatz aus der Tabelle Objekte
können in unterschiedlichen Feldern mehrere Adressen zugeordnet sein,
z.B. eine für den Standort des Objektes, eine für den
Rechnungempfänger und eine für die verantwortliche
Instandsetzungsfirma. Diese drei Adressen eines Objektes haben
untereinander nicht wirklich etwas mit einander zu tun, deshalb
müsste ich quasi drei Beziehungen zwischen den zwei Tabellen
definieren und da knallt's schon bei der zweiten....
also ich würde der Tabelle Objekte ein ID-Autowertfeld als PK spendieren
und dann in der Adress-Tabelle
Objekt-Id als Referenz zu den Objekten
Adress-Art (Standort, Rechnungsempfänger, verantwortliche Instandsetzungsfirma)
Adress-Felder

wenn nun noch Adressen in mehreren Adressarten gleichzeitig auftauchen können,
kann man sogar eine 3. Tabelle dazwischen schalten.

Selbst wenn Standort und Rechnungsempfänger zum größten Teil identisch
sein sollten, muß nicht die Rechnungs-Anschrift extra erfasst werden, da man
durch geschicktes View-Design für jedes Objekt eine Rechnungsanschift
bekommt: wenn vorhanden dann Rechnung, sonst Standort.

Gruß Jürgen
Dieter Liessmann
2005-09-30 13:32:19 UTC
Permalink
Hi Daniel,
Post by
Hallo Dieter!
< geklärte Missverständnisse gesnipt>
Post by
Post by Dieter Liessmann
Klar kann man Beziehungen auch über mehrere Felder definieren.
Ok, hier muss ich mich erstmal selbst bissl verhauen, da ich das
Problem mit den Beziehungen zwar zwar nicht völlig aber zumindest
etwas anders im Hinterkopf hatte.
Also ... Deshalb jetzt die Strukturen, die eine Lösung über
Angenommen es gibt eine Adressen-Tabelle (wie ich sie bereits
aufgeführt hatte) und eine Tabelle mit Objekten (Häuser, installierte
Heizungen oder derartiges). Einem Datensatz aus der Tabelle Objekte
können in unterschiedlichen Feldern mehrere Adressen zugeordnet sein,
z.B. eine für den Standort des Objektes, eine für den
Rechnungempfänger und eine für die verantwortliche
Instandsetzungsfirma. Diese drei Adressen eines Objektes haben
untereinander nicht wirklich etwas mit einander zu tun, deshalb
müsste ich quasi drei Beziehungen zwischen den zwei Tabellen
definieren und da knallt's schon bei der zweiten....
Das Einführen der FOREIGN KEY-Einschränkung 'FK_Tab1_Tab2_2' für die
Tab2-Tabelle kann Schleifen oder mehrere kaskadierende Pfade
verursachen. Geben SIE ON DELETE NO ACTION oder ON UPDATE NO ACTION
an, oder ändern Sie andere FOREIGN KEY-Einschränkungen.
Man kann aber für keine der Beziehungen das Update weglassen, da das
doch wieder inkonsistente Zustände zur Folge hätte.
UND: Ich weiß, dass man das eigentlich auf mehrere Tabellen auftrennen
(normalisieren) müsste und es dann wieder gehen würde.
Hm, leider widersprichst Du Dir schon wieder selbst.
Ich zitiere mal aus anderer Stelle aus diesem thread:
<Zitat Anfang>
Post by
Post by Dieter Liessmann
Ja und ich weiss, dass es bei zirkulären Beziehungen so nicht
mehr geht, nur das gibt das Dein Beispiel nicht her.
Zirkuläre Bezüge kommen bei uns nicht vor.
<Zitat Ende>

Genau das hast Du hier!

Ich bin im Moment grad dabei eine von uns erstellte Buchhaltung von A97
Jet3.5 auf den SQL-Server zu heben.
Sollte Dir als Wirtschaftsinformatiker ja was sagen ;-)
Dort hab ich exakt dieses Problem mit dem Kontenstamm.
Ich hab noch den Vorteil, dass ich nicht in einer Beziehung mehrere Felder
habe.
Nach langem grübeln bin ich hier auch zu dem Entschluss gekommen das mit
Triggern zu lösen.
Dabei blieb es mir aber nicht erspart in die Tabelle Kontenstamm eine neu ID
als Identität einzubauen.

Als kleine Anregung hier meine Trigger.
Meine Mastertabelle hat den namen Kontenstamm, eine der betroffenen
Detailtabellen nenn ich jetzt mal Buchungsjournal.
Das wichtigste Merkmal des Kontos ist seine Nummer, bei mir im Feld Konto
als integer.
Mein neuer PK in Kontenstamm ist Konto_ID.
Ich hab mir dann pro Feld zwei Trigger gemacht, weil ich das einfach
übersichtlicher finde:

CREATE TRIGGER trg_Kontenstamm_BuchungsjournalHabenUpdate
on dbo.Kontenstamm
FOR UPDATE AS
IF UPDATE(Konto)
UPDATE Buchungsjournal SET Habenkonto=Inserted.Konto
FROM
Buchungsjournal INNER JOIN Deleted ON
Buchungsjournal.Habenkonto=Deleted.Konto
INNER JOIN Inserted ON Deleted.Konto_ID=Inserted.Konto_ID

Hier kann man prima sehen wie in einem Trigger der zustand vor der Änderung
(Deleted) und nach der Änderung (inserted) benutzt wird.

Der zweite Trigger gibt mir dann ne Meldung bei versuchter Löschung:

CREATE trigger trg_Kontenstamm_BuchungsjournalHabenDelete
on dbo.Kontenstamm
FOR DELETE AS
IF(
SELECT Count(*)
FROM Buchungsjournal INNER JOIN Deleted ON
Buchungsjournal.Habenkonto = Deleted.Konto
) > 0
BEGIN
RAISERROR 55555 'Dieses Konto kann nicht gelöscht werden, da es
bereits benutzt wurde!'
ROLLBACK TRANSACTION
END

Hoffe das gibt dir nen brauchbaren hinweis für die Verwendung der
Pseudotabellen deleted und inserted.
Aber da is wirklich die Original-Doku zum SQL-Server zum Thema Trigger
spitze! Sind auch prima Beispiele drin.
Damit und mit einigen NG's (nicht zuletzt Elmars Antworten) hab ich mir auch
den SQL-Server angeeignet.
Post by
zu
Post by Dieter Liessmann
Kannst Du mit einem Aufwand von ca. 5 Minuten an dem Beispiel von
Elmar prüfen.
und
Post by Dieter Liessmann
Wenn jemand so nett ist und Dir ein komplettes Skript als Beispiel
liefert, dass Du nur per Copy and Paste ausprobieren kannst,
solltest Du so nett sein dies wenigstens mal auszuprobieren. Dann
tritt auch sehr schnell ein Lerneffect ein.
Post by
Ich hab ja auch nicht gesagt, dass Elmars Code nicht funktioniert.
Ich war mir sicher, dass Elmars Code funktioniert und konnte mir auch
vorstellen wie, ohne das wirklich auszuprobieren. Allerdings deckte
es eben das o.g. Problem nicht ab, da er immer nur eine Beziehung
zwischen zwei Tabellen hatte (weil ich dieses Strukturbeispiel nicht
aufgeführt hatte).
Post by Dieter Liessmann
Soweit die direkten Antworten. Nun noch etwas allgemeinere
Betrachtungen. Deine eigenen Aussagen waren etwas gegensätzlich, so
dass es schwierig ist dir "auf den Punkt" zu helfen.
Ich weiß, aber es ist halt schwer die tatsächliche Situation genauer
zu beschreiben, dabei aber "anonym" zu bleiben.
Hm, evtl hättest Du dir doch mal kurz die Mühe machen sollen in einer
kleinst-Datenbank dein Problem nachzustellen, mit dem Enterprise-Manager ein
Skript erstellen und das hier posten.
Post by
Post by Dieter Liessmann
Erst erweckst Du den Eindruck, dass Du an dem Backend nichts ändern
kannst, dann räumst Du das aber doch ein.
Klingt sicher blöd aber genauso ist es. Es wird in Zukunft Fälle
geben, wo wir das können (könnten) und Fälle wo nicht. Wir streben
aber lieber eine Lösung an, die für beide (und eventuell in Zukunft
weiteren) Fälle gleichermaßen umsetzbar ist. Ich will das aber hier
nicht noch weiter ausbauen, ich denke der Thread ist schon lang
genug. Bitte nehmt es einfach so hin, dass ich nur einen Workaround
für eine bereits vermurkste Datenstruktur gesucht habe.
Post by Dieter Liessmann
Du kannst "problemlos" Änderungen am Backend vornehmen obwohl schon
1000ende von Kunden damit arbeiten.
Nur wenn es "Dein" Backend ist. Ansonsten bekommt der Kunde Probleme
mit der anderen Software.
Post by Dieter Liessmann
Alle Änderungen lassen sich durch SQL-Statements automatisieren. Du
musst also bei deinen Kunden nur ein Skript laufen lassen.
Das wir die Datenbank nach Belieben umgestalten könnten, weiß ich.
Aber wir können leider die Fremdsoftware nicht so umprogrammieren,
dass sie mit unserer Vorstellung der Datenbank funktioniert.
OK, verstanden. Mal zusammengefasst:
Du kannst bedingt Änderungen am Backend machen, wenn diese vorher mit den
Kollegen abgestimmt sind die die andere Software bauen (gebaut haben) die
auf das gleiche Backend zugreift.
Post by
Post by Dieter Liessmann
können. Auch das Handling (gerade von Triggern) ist einfacher, wenn
Du in einem solchen Fall in deiner Mastertabelle eine
Identitätsspalte einbaust und die Beziehung darüber herstellst.
Das geht ja in die Richtung, die Stefan vorgeschlagen hatte und wenn
ich ihn richtig verstanden habe bräuchte ich dann nicht mal eine
Beziehung zu den Detailtabellen, sondern könnte dann in den Triggern
"manuell" eine Zuordnung zwischen inserted- und deleted-Tabelle
herstellen und die entsprechend weitergeben.
Stimmt. Siehe mein Beispiel oben zur Buchhaltung.
Post by
Post by Dieter Liessmann
Ausserdem fällt mir im Moment auch kein praktisches Beispiel ein in
dem sauber normalisiert wurde und eine Beziehung über mehrere Felder
nötig ist (kann aber auch an meiner mangelnden Phantasie liegen ;-)).
Es ist ja nicht sauber normalisert, hab ich doch schon mehrfach
zugegeben. Und warum das nicht so einfach ist auch.
Na ja, hast dich halt bissl verquast ausgedrückt. So ein einfacher Satz wie
oben bei OK (wenn er denn stimmt ;-)) hätts verständlicher gemacht.
Post by
Post by Dieter Liessmann
USE tempdb
[...]
Hab mir diesmal die "Mühe" gemacht und es ausprobiert und es hat
funktioniert. Hatte ich aber auch nicht anders erwartet. Es deckt nur
leider das Problem der mehrfachen Beziehung zwischen zwei Tabellen
nicht ab. Sorry, dass ich das bisher nicht eher etwas besser
beschrieben hatte, aber ich hab "den Verantwortlichen" erst heute mal
wieder zu fassen
bekommen.
OK. Hoffe das genannte Buchhaltungsbeispiel hilft jetzt weiter ??
--
So long Dieter
2005-09-30 14:57:37 UTC
Permalink
Hallo Dieter!
Post by Dieter Liessmann
Hm, leider widersprichst Du Dir schon wieder selbst.
<Zitat Anfang>
Post by
Post by Elmar Boye
Ja und ich weiss, dass es bei zirkulären Beziehungen so nicht
mehr geht, nur das gibt das Dein Beispiel nicht her.
Zirkuläre Bezüge kommen bei uns nicht vor.
<Zitat Ende>
Genau das hast Du hier!
Unter eine Zirkulären Beziehung würde ich verstehen, wenn der PK aus
"Adressen" ein FK in "Objekte" ist und der PK aus "Objekte" wiederum ein FK
in "Adressen". Richtig?
Das ist aber nicht der Fall, sondern der PK aus "Adressen" steht nur in
mehreren Feldern in "Objekte" als Fremdschlüssel drin. Diese Felder haben
aber untereinander keinen Bezug zueinander, es sind da (in "Objekte") also
völlig beliebige Kombinationen möglich.
Oder zählt das auch als zirkulärer Bezug?
Post by Dieter Liessmann
Ich bin im Moment grad dabei eine von uns erstellte Buchhaltung von A97
Jet3.5 auf den SQL-Server zu heben.
Sollte Dir als Wirtschaftsinformatiker ja was sagen ;-)
Hab ich glaub ich mal von gehört ;)
Nee quatsch, im Prinzip machen wir gerade das selbe (durch).
Post by Dieter Liessmann
Dort hab ich exakt dieses Problem mit dem Kontenstamm.
Ich hab noch den Vorteil, dass ich nicht in einer Beziehung mehrere Felder
habe.
Das war ein Irrtum meinerseits. Das haben wir zwar auch (Beziehungen über
mehrere Felder), aber das Problem ist eher, das wir eben manchmal mehrere
Beziehungen zwischen zwei Tabellen (mit je einem Feld) benötigen, weshalb
wir uns auch für Trigger entschieden haben.
Post by Dieter Liessmann
Nach langem grübeln bin ich hier auch zu dem Entschluss gekommen das mit
Triggern zu lösen.
Ich hab mir dann pro Feld zwei Trigger gemacht, weil ich das einfach
Wir auch, eigentlich sogar drei (INSERT, UPDATE, DELETE)
Post by Dieter Liessmann
CREATE trigger trg_Kontenstamm_BuchungsjournalHabenDelete
on dbo.Kontenstamm
FOR DELETE AS [...]
Der sieht bei uns ähnlich aus, zumindest für Beziehungen ohne
Löschweitergabe, ansonsten halt DELETE FROM .....

Allerdings wirkt
Post by Dieter Liessmann
IF(
SELECT Count(*)
FROM Buchungsjournal INNER JOIN Deleted ON
Buchungsjournal.Habenkonto = Deleted.Konto
bei einem Trigger, der für für eine Aktion, die mehrere Masterdatensätze
betrifft (DELETE FROM Kontenstamm WHERE Konto LIKE ...) für meine Begriffe
nicht so, wie ich mir
das wünschen würde. Das bricht nämlich immer ab, sobald für EIN zu
löschendes Konto Detaildatensätze vorhanden sind, obwohl man ja das eine
oder andere Konto (ohne Detailsatensätze) schon mal löschen könnte. Aber im
Sinne einer Transaktion ist Dein Beispiel natürlich richtig.
Post by Dieter Liessmann
Als kleine Anregung hier meine Trigger.
Dabei blieb es mir aber nicht erspart in die Tabelle Kontenstamm eine neu
ID als Identität einzubauen.
Mein neuer PK in Kontenstamm ist Konto_ID.
Ich will das eigentlich vermeiden, neue PK's einzufügen und kann es
teilweise auch gar nicht! Hab ich glaub ich nun oft genug gesagt...
Post by Dieter Liessmann
CREATE TRIGGER trg_Kontenstamm_BuchungsjournalHabenUpdate
[...]
UPDATE Buchungsjournal SET Habenkonto=Inserted.Konto
FROM
Buchungsjournal INNER JOIN Deleted ON
Buchungsjournal.Habenkonto=Deleted.Konto
INNER JOIN Inserted ON Deleted.Konto_ID=Inserted.Konto_ID
Das funktioniert aber eben nicht mehr, wenn der PK (Konto_ID) geändert wird!
Post by Dieter Liessmann
Damit und mit einigen NG's (nicht zuletzt Elmars Antworten) hab ich mir
auch den SQL-Server angeeignet.
Ja, der Elmar ist wirklich spitze!
Post by Dieter Liessmann
Hm, evtl hättest Du dir doch mal kurz die Mühe machen sollen in einer
kleinst-Datenbank dein Problem nachzustellen, mit dem Enterprise-Manager
ein Skript erstellen und das hier posten.
Ja, im Nachhinein betrachtet wäre das wahrscheinlich besser gewesen. Aber
wenn man selbst schon zu tief drin steckt, dann kann man manche
Verständnisprobleme einfach nicht mehr nachvollziehen. Vor allem, wenn man
schon paar Mal versucht hat die zu erläutern.
Post by Dieter Liessmann
Du kannst bedingt Änderungen am Backend machen, wenn diese vorher mit den
Kollegen abgestimmt sind die die andere Software bauen (gebaut haben) die
auf das gleiche Backend zugreift.
Kollegen? Abgestimmt? Die husten uns was...
Wir nehmen einfach nur den ihr System (genauer: ihre Datenbank) und legen da
zusätzliche Tabellen an. Wir haben Beziehungen zwischen unseren Tabellen,
teilweise aber auch zu den ihren Tabellen. Unsere Anwendung greift sowohl
auf unsere, als auch auf deren Tabellen zu.

Aber Schluß jetzt und diesmal bitte wirklich. Ich habe alle nötigen Aussagen
zusammen, die ich brauche. Der erste Schritt wird sein, die Trigger so zu
erweitern, dass sie einen Fehler werfen, wenn die Aktion für mehrere
Master-Datensätze gilt. Diese "Ausnahmefälle" müssen dann eben über
spezielle SP's, oder client-seitige Logik implementiert werden.

Mit freundlichen Grüßen
Daniel Barisch

Elmar Boye
2005-09-29 11:19:29 UTC
Permalink
Hallo Daniel,

Daniel Barisch <Daniel Barisch> schrieb ...
Post by
Gleich mal vorneweg.... Ich möchte hier niemandem auf den Schlips
treten oder so.
ich trage keine Schlipse, also kann mir nie auf denselben treten ;-).
Post by
Ich will hier sicher nicht alles als "Theorie" abtun! Zum einen, weil
die DB nicht auf meinem Mist gewachsen ist, zum anderen (im
speziellen Fall der Text-PK's) aber auch,
Wenns die Anwendungen hergeben, würde ich würde zwar wegen
"Sued" <-> "Süd" für eine separate Bezeichnungsspalte plädieren,
denn das ist schon etwas krude (und eigentlich teuer mehr dazu unten)...
Und evtl. gäbe es über Sichten etc. die Möglichkeit das vor alten
"dummen" Anwendungen zu verstecken.
Und ein hier irgendwo gebrachtes Argument bezüglich der paar Joins
ziehen bei heutigen Datenbanken eher wenig.

Und wenn man eine Anwendung migriert, sollte man das meiner Meinung
nach, auch bei den Frontends versuchen. Und neue Erkenntnisse
bei der Gelegenheit einfliessen lassen.

Aber sparen wir uns das für eine andere Diskussion für später auf.
Post by
weil ich GUID-Schlüssel einfach nicht für sinnvoll/erforderlich halte,
wenn durch das DBMS die ref. Integrität sichergestellt werden kann
(an dieser Stelle mal abstrahiert von der tatsächlichen Umsetzung).
Wiederholt: Man benötigt (hier) keine Guids.
Die im übrigen häufig von Entwicklern am meisten "geliebt" werden,
die mit ADO.NET etc. Probleme haben. (Und da gilt: siehe unten).

Da müsste mir jemand schon mehr als mit "wirtschaftliche Lösung"
als Begründung daher kommen, wie z. B. Replikation, *echt verteilte*
Anwendung usw.
Post by
Post by Elmar Boye
Post by
Um das am schnellsten zu realisieren würde mir als erstes folgendes
einfallen...
UPDATE Adressgruppen SET Name = Replace(Name, 'Sued', 'Süd)'
Und das heisst dann: Wo ist da ein Problem...
UPDATE dbo.Adressgruppen SET Name = Replace(Name, 'Sued', 'Süd')
-- wir gehen stillschweigend von genügend Platz aus
UPDATE dbo.Banken SET Name = Replace(Name, 'KSK-', 'Volkcenter ')
SELECT * FROM dbo.Adressen
GO
Dann habe ich Adressen, wo immer noch die alte Gruppe/Bank drin
steht,
Hast Du Dir die Ausgabe überhaupt mal angeguckt???
Post by
weil unsere (AFTER-) UPDATE-Trigger im jetzigen Stand nur den
PK-Wert des letzten Datensatzes aus der inserted und deleted Tabelle
auslesen und mit diesen die Aktualisierungsweitergabe durchführen.
Wenn Du Deine Trigger wegwirfst und durch die FOREIGN KEY Einschränkungen
wie im Beispiel ersetzt (übrigens so wie in Access/Jet), sind die
Adressen gleich mit korrigiert.

Umd das gefahrlos für Deine vollständigen Daten auszuprobieren
verwende eine Kopie in tempdb wie auch das Beispiel.
Post by
Wird jeweils nur ein Datensatz geändert, dann steht in diesen temp.
Tabellen ja auch jeweils nur ein Datensatz drin. Werden mehrere
Datensätze geänderten dann erwische ich mehr oder weniger zufällig
zwei PK-Werte, die (wie ich gelernt habe), streng genommen nicht mal
zusammenpassen müssen (alt -> neu).
Post by Elmar Boye
Mit Triggern gehts genauso...
Den Satz hätte ich nicht "..." sollen, da er aus dem Zusammenhang
gerissen ist (er wurde vor dem Erstellen des UPDATE Beispiel geschrieben).
Post by
Ich sehe bisher keine Möglichkeit, einen eindeutigen Zusammenhang
zwischen den einzelnen Datensätzen in Detail-Daten-, inserted- und
deleted-Tabelle herzustellen, so dass ich Datensätze mit dem alten Wert
(aus deletetd) in der Detail-Datentabelle selektieren und mit dem
neuen Wert (aus inserted) aktualisieren könnte.
Denn gibts nicht. Somit wäre das obige UPDATE mit jeder Form
von Trigger nicht umsetzbar. Der Trigger müsste wie schon gezeigt
Änderungen mehrerer Zeilen verweigern.
Das könnte nur eine Prozedur leisten, die jedoch ebenso mit
beliebigem Clientcode (ADO/ADO.NET geschrieben sein könnte).

Exemplarisch für
-- UPDATE dbo.Adressgruppen SET Name = Replace(Name, 'Sued', 'Süd')

DECLARE @name varchar(30)
DECLARE AdressgruppenCursor CURSOR
LOCAL STATIC -- STATIC bzw. INSENSITIVE muss sein!
FOR SELECT Name FROM dbo.Adressgruppen
WHERE name LIKE '%Sued%'

OPEN AdressgruppenCursor
FETCH NEXT FROM AdressgruppenCursor INTO @name
WHILE @@FETCH_STATUS = 0
BEGIN
UPDATE dbo.Adressgruppen
SET Name = Replace(Name, 'Sued', 'Süd')
WHERE name = @name

FETCH NEXT FROM AdressgruppenCursor INTO @name
END
CLOSE AdressgruppenCursor
DEALLOCATE AdressgruppenCursor
GO

Ja ich weiss: Viel Holz für fast nichts...
Und nochmals NEIN: Im Trigger geht das nicht.

Und die Kopierlösung wäre zwar insofern besser in SQL geschrieben
als sie aus INSERT ... SELECT und späterem DELETE bestände...
aber würde dann über Anweisungen für alle beteiligten Tabellen
(also Adressen + Adressgruppen, Adressen + Banken)
Was in realen Datenbank schon einige Dutzend bis Hunderte
Anweisungen werden können - naja mit der Cursor nehme man
alles mal Zwanzig...

(Kein Beispiel - ich muss jetzt was essen)

Und auch das geht nicht mit einem Trigger.
Allerdings könnte der FOREIGN KEY ohne UPDATE CASCADE eine
leichtsinnige Änderung des Primärschlüssel verhindern.
Post by
Post by Elmar Boye
Ja und ich weiss, dass es bei zirkulären Beziehungen so nicht
mehr geht, nur das gibt das Dein Beispiel nicht her.
Zirkuläre Bezüge kommen bei uns nicht vor.
Und so würde ich zu den FOREIGN KEY CONSTRAINTS mit UPDATE/DELETE
CASCADE greifen. Denn nur damit geht das UPDATE da oben - also
über mehrere Zeilen.

Und im Trigger - wenn überhaupt noch notwendig - nur für Aufgaben,
die kein Constraint (siehe auch den CHECK im Beispiel) übernehmen kann.
Post by
Post by Elmar Boye
Na und? Ich denke, Du bist ein Entwickler, das sind endlich
mal Herausforderungen ;-)
Herausforderungen die ich aus technischer Sicht sehr gern annehmen
würde, aber aus wirtschaftlicher (Zeit/Kosten) und praktischer
(Fremdsystem!) Sicht nicht angehen kann.
Nimms mir nicht übel: Diese Sätze höre ich (leider) meistens
immer dann, wenn die Leute von den technischen Möglichkeiten
zu wenig Kenntnis haben. Und das dazu führt, dass eine Lösung
zuviel Zeit kostet und so als "unwirtschaftlich" eingestuft wird.

Nur ist das ein Verdrehen von Ursache und Wirkung.

Wobei: Gespart wird wenig bis gar nichts, denn am Ende schreibt (fällt)
man das Holz (mit obigem Cursor) an anderer Stelle, was viel Zeit
(Geld) kostet.

Wobei: Wenn man das oben angesprochene Aufteilen in eine Anzeigespalte
und Primärschlüssel betrachtet, was ein Entwickler genau deswegen
vornehmen sollte - siehts erst richtig traurig aus.
(Und NEIN: das muss immer noch keine Identity, Guid Spalte beim
Primärschlüssel sein, notfalls kann man auch mit "Sued-A" (PK)
= "Südbayern rechts von Passau" (Anzeige) leben).
Post by
Post by Elmar Boye
Damit das mit (damaligen) nicht immer passiert empfehle ich
etwas mehr Lektüre...
Da bin ich ja gerade dabei, aber es geht nun mal nicht alles auf
einmal. Und ihr helft mir nunmal immer so nett, das verwöhnt...
Kontinuierliche Weiterbildung hilft am ehesten...
(Ich mache das auch schon bald 20 Jahre und hatte anfangs von
relationalen Datenbanken auch herzlich wenig Ahnung, habe auch
kein Informatik Diplom...)

Gruss
Elmar
2005-09-29 13:02:15 UTC
Permalink
Hallo Elmar!
Post by Elmar Boye
Und wenn man eine Anwendung migriert, sollte man das meiner Meinung
nach, auch bei den Frontends versuchen. Und neue Erkenntnisse
bei der Gelegenheit einfliessen lassen.
Dafür bin ich doch auch! Aber das musst Du erstmal dem Hersteller des
Fremdsystems klar machen, in das wir uns einklinken.
Post by Elmar Boye
Aber sparen wir uns das für eine andere Diskussion für später auf.
DANKE!!!
Post by Elmar Boye
Hast Du Dir die Ausgabe überhaupt mal angeguckt???
Nein! Ich bin mir sicher, dass Dein Code funktioniert. Aber (wie oft denn
noch), wir haben auch Beziehungen mit mehreren Feldern und das deckt Dein
Beispiel leider nicht ab.
Post by Elmar Boye
Wenn Du Deine Trigger wegwirfst und durch die FOREIGN KEY Einschränkungen
wie im Beispiel ersetzt (übrigens so wie in Access/Jet), sind die
Adressen gleich mit korrigiert.
Geht das denn auch über mehrere Felder? Ich komm ja nicht dazu, mich mal
damit zu beschäftigen.
Post by Elmar Boye
Umd das gefahrlos für Deine vollständigen Daten auszuprobieren
verwende eine Kopie in tempdb wie auch das Beispiel.
So neu bin ich nun auch wieder nicht in dem Thema ;)
Post by Elmar Boye
Post by
Ich sehe bisher keine Möglichkeit, einen eindeutigen Zusammenhang
zwischen den einzelnen Datensätzen in Detail-Daten-, inserted- und
deleted-Tabelle herzustellen, so dass ich Datensätze mit dem alten Wert
(aus deletetd) in der Detail-Datentabelle selektieren und mit dem
neuen Wert (aus inserted) aktualisieren könnte.
Denn gibts nicht. Somit wäre das obige UPDATE mit jeder Form
von Trigger nicht umsetzbar. Der Trigger müsste wie schon gezeigt
Änderungen mehrerer Zeilen verweigern.
Das könnte nur eine Prozedur leisten, die jedoch ebenso mit
beliebigem Clientcode (ADO/ADO.NET geschrieben sein könnte).
Hatte ich das nicht schon vor etlichen Postings festgestellt und wollte das
an der Stelle eigentlich beenden?
Post by Elmar Boye
Post by
Post by Elmar Boye
Na und? Ich denke, Du bist ein Entwickler, das sind endlich
mal Herausforderungen ;-)
Herausforderungen die ich aus technischer Sicht sehr gern annehmen
würde, aber aus wirtschaftlicher (Zeit/Kosten) und praktischer
(Fremdsystem!) Sicht nicht angehen kann.
Nimms mir nicht übel: Diese Sätze höre ich (leider) meistens
immer dann, wenn die Leute von den technischen Möglichkeiten
zu wenig Kenntnis haben. Und das dazu führt, dass eine Lösung
zuviel Zeit kostet und so als "unwirtschaftlich" eingestuft wird.
Nur ist das ein Verdrehen von Ursache und Wirkung.
Ich bin leider nicht der, der letztendlich zwischen wirtschaftlich und
unwirtschaftlich entscheidet und die Termine setzt. Und das ich nicht alle
technischen Möglichkeiten kenn, habe ich ja bereits zugegeben. Deshalb hatte
ich ja ursprünglich gefragt.
Post by Elmar Boye
Kontinuierliche Weiterbildung hilft am ehesten...
Mach ich ja (gerade)...
Post by Elmar Boye
(Ich mache das auch schon bald 20 Jahre und hatte anfangs von
Öhm, ich bin erst, na ja zumindest noch lange nicht so alt, äh tschuldigung,
reich an Erfahrung.
Post by Elmar Boye
relationalen Datenbanken auch herzlich wenig Ahnung, habe auch
kein Informatik Diplom...)
Ohne angeben zu wollen (wirklich nicht!) ich hab eins als Wirtsch.-Inf.,
aber das nützt mir hier halt nur bedingt, da es, wie Du schon sagtest, ohne
kontinuierliche Weiterbildung nicht geht...


Mit freundlichen Grüßen
Daniel Barisch
Elmar Boye
2005-09-29 14:17:37 UTC
Permalink
Daniel Barisch <Daniel Barisch> schrieb ...
Post by
Nein! Ich bin mir sicher, dass Dein Code funktioniert. Aber (wie oft
denn noch), wir haben auch Beziehungen mit mehreren Feldern und das
deckt Dein Beispiel leider nicht ab.
Na, dann liefere die passenden Ausgangsbeispiele ;-)
Post by
Post by Elmar Boye
Wenn Du Deine Trigger wegwirfst und durch die FOREIGN KEY
Einschränkungen wie im Beispiel ersetzt (übrigens so wie in
Access/Jet), sind die Adressen gleich mit korrigiert.
Geht das denn auch über mehrere Felder?
Es geht!
Post by
Ich komm ja nicht dazu, mich mal damit zu beschäftigen.
Wenn Du mal in die Dokumentation zu
ALTER TABLE
guckst brauchst Du Dir nichts falsches mehr erzählen lassen.

Die deutsche Dokumentation gehört auf jeden Entwicklungsrechner:
http://www.microsoft.com/downloads/details.aspx?FamilyId=A6F79CB1-A420-445F-8A4B-BD77A7DA194B&displaylang=de
Ersatzweise erstmal in englisch
http://msdn.microsoft.com/library/en-us/tsqlref/ts_aa-az_3ied.asp?frame=true
und etwas weniger trocken und mehr Grundlagen:
http://msdn.microsoft.com/library/en-us/createdb/cm_8_des_04_9183.asp?frame=true

Also genauso geht - mit bis zu 16 Spalten:
ALTER TABLE dbo.Tabelle
ADD CONSTRAINT FK_Tabelle_PrimärschlüsselTabelle
FOREIGN KEY (Spalte1, Spalte2 /*, ... bis 16*/)
REFERENCES dbo.PrimärschlüsselTabelle (Spalte1, Spalte2 /*, ... bis 16 */
ON UPDATE CASCADE

Gruss
Elmar
Günther Bach
2005-09-27 18:58:31 UTC
Permalink
Post by
Aber bist Du Dir sicher, dass das so funktioniert?
Ja, garantiert!
Post by
Irgendwie fehlt mir da
ein Bezug zur deleted-Tabelle, um die richtigen Detaildatensätze
auszuwählen.
Das war ja auch ein UPDATE-Trigger (bzw. INSTEAD OF UPDATE, weil der
dämliche SQL-Server massive Probleme mit TEXT-Feldern hat), hier noch
der DELETE- und INSTEAD OF INSERT-Trigger:


CREATE TRIGGER [xxxx_DELETE] ON dbo.tab_xxxx
FOR DELETE
AS

BEGIN

DECLARE xxxx_delete_cursor CURSOR LOCAL FOR SELECT xxxx_id
FROM deleted

DECLARE @IntID int

OPEN xxxx_delete_cursor

FETCH NEXT FROM news_delete_cursor INTO @IntID

WHILE @@FETCH_STATUS = 0
BEGIN
-- Entsprechende Einträge in yyyyy und zzzzz löschen
-- Reihenfolge beachten, falls diese Tabellen
ebenfalls Trigger auslösen!
DELETE FROM yyyyy WHERE yyyy_id = @IntID

DELETE FROM zzzzz WHERE (zzzz_id = @IntID)

FETCH NEXT FROM xxxx_delete_cursor INTO @IntID
END

CLOSE xxxx_delete_cursor
DEALLOCATE xxxx_delete_cursor

END







CREATE TRIGGER [Nxxxx_INSERT] ON dbo.tab_xxxx
INSTEAD OF INSERT
AS
BEGIN
DECLARE @IntID INT

-- INSERT ausführen
INSERT INTO tab_xxxx (
xxxx_id,
xxxx_datum)
SELECT
i.xxxx_id,
i.xxxx_datum
FROM inserted i

-- ID von INSERT holen
SELECT @IntID = SCOPE_IDENTITY()
-- ANZAHL der Einträge
DECLARE @anzahl int
SELECT @anzahl = count(*) FROM inserted
DECLARE @zaehler int
SELECT @zaehler = 0


WHILE @zaehler<@anzahl
BEGIN

-- und viel mehr Code

SELECT @zaehler = @zaehler + 1
SELECT @IntID = @IntID -1
END

END
2005-09-28 07:43:25 UTC
Permalink
Hallo Günther!
Post by Günther Bach
Post by
Aber bist Du Dir sicher, dass das so funktioniert?
Ja, garantiert!
Post by
Irgendwie fehlt mir da
ein Bezug zur deleted-Tabelle, um die richtigen Detaildatensätze
auszuwählen.
Das war ja auch ein UPDATE-Trigger (bzw. INSTEAD OF UPDATE, weil der
dämliche SQL-Server massive Probleme mit TEXT-Feldern hat),
Na dann würde mich aber mal interessieren, wie in
Post by Günther Bach
CREATE TRIGGER [xxxx_UPDATE] ON dbo.tab_xxxx
INSTEAD OF UPDATE
AS
BEGIN
[..]
BEGIN
-- Hier jetzt die ganzen SQL-Abfragen
UPDATE tab_xxxx
SET
tab_xxxx.xx_id = i.x_id
FROM inserted i
-- usw.....
END
[...]
Die SQL-Abfragen zur Aktualiserung der Detailtabellen aussehen. Woher nimmst
Du denn den "alten" Wert, um überhaupt erstmal die zu ändernden
Detaildatensätze auszuwählen? Um den Masterdatensatz zu aktualiseren brauch
ich keinen Trigger, das kann der SQL Server auch allein.

Mit freundlichen Grüßen
Daniel Barisch
Günther Bach
2005-09-28 09:40:30 UTC
Permalink
Post by
Post by Günther Bach
Das war ja auch ein UPDATE-Trigger (bzw. INSTEAD OF UPDATE, weil der
dämliche SQL-Server massive Probleme mit TEXT-Feldern hat),
Na dann würde mich aber mal interessieren, wie in
Post by Günther Bach
CREATE TRIGGER [xxxx_UPDATE] ON dbo.tab_xxxx
INSTEAD OF UPDATE
AS
BEGIN
[..]
BEGIN
-- Hier jetzt die ganzen SQL-Abfragen
UPDATE tab_xxxx
SET
tab_xxxx.xx_id = i.x_id
FROM inserted i
-- usw.....
END
[...]
Die SQL-Abfragen zur Aktualiserung der Detailtabellen aussehen. Woher nimmst
Du denn den "alten" Wert, um überhaupt erstmal die zu ändernden
Detaildatensätze auszuwählen?
In "inserted" hast Du die neuen Daten und in "tab_xxxx" die alten.

Bei "-- usw" kommen dann noch ca. 300 Zeilen SQL-Anweisungen, auch die
UPDATE-Abfrage ist massiv gekürzt.
Post by
Um den Masterdatensatz zu aktualiseren brauch
ich keinen Trigger, das kann der SQL Server auch allein.
Bei Textfeldern gibt es mit dem normalen Trigger Probleme, daher muss
man "INSTEAD OF"-Trigger benutzen und bei den "INSTEAD OF"-Triggern
muss man auch den Masterdatensatz aktualisieren, das macht der
SQL-Server dann nämlich nicht mehr.
Aber auch dann kann man sich nicht auf die Trigger verlassen. Irgendwo
(afaik bei einigen 100 kB) schneiden einige SQL-Server-Funktionen den
Inhalt von Textfeldern trozdem ab.


Meine Trigger lösen andere Probleme als Du hast, daher spielt der
Inhalt (in meinen Augen) keine Rolle.
Ich dachte, Du wolltest nur wissen, wie man in Triggern Schleifen
"programmiert", um alle von einer Änderung betroffenen Datensätze zu
erfassen.
Und das tun meine Beispiele.

CU,
Günther
2005-09-28 11:32:16 UTC
Permalink
Hallo Günther!
Post by Günther Bach
Post by
Na dann würde mich aber mal interessieren, wie in
Post by Günther Bach
CREATE TRIGGER [xxxx_UPDATE] ON dbo.tab_xxxx
INSTEAD OF UPDATE
[...]
Die SQL-Abfragen zur Aktualiserung der Detailtabellen aussehen. Woher nimmst
Du denn den "alten" Wert, um überhaupt erstmal die zu ändernden
Detaildatensätze auszuwählen?
In "inserted" hast Du die neuen Daten und in "tab_xxxx" die alten.
Mmh, hatte doch'n Brett vor'm Kopf. Bei nem INSTEAD OF-Trigger ist ja an dem
Masterdatensatz noch nichts passiert. Allerdings stellt sich mir die Frage
jetzt genau andersrum. Für meine Begriffe kann doch über
Post by Günther Bach
-- Hier jetzt die ganzen SQL-Abfragen
UPDATE tab_xxxx
SET
tab_xxxx.xx_id = i.x_id
FROM inserted i
wieder keine Zuordnung hergestellt werden, da die alte "xx_id" im Datensatz
von "tab_xxxx" nicht mit dem Wert aus der inserted-Tabelle übereinstimmt.
Post by Günther Bach
Bei Textfeldern gibt es mit dem normalen Trigger Probleme, daher muss
man "INSTEAD OF"-Trigger benutzen und bei den "INSTEAD OF"-Triggern
muss man auch den Masterdatensatz aktualisieren, das macht der
SQL-Server dann nämlich nicht mehr.
Das war mir eigentlich klar, aber dass da die alten Werte noch drin stehen
irgendwie nicht. Böses Brett...
Post by Günther Bach
Aber auch dann kann man sich nicht auf die Trigger verlassen. Irgendwo
(afaik bei einigen 100 kB) schneiden einige SQL-Server-Funktionen den
Inhalt von Textfeldern trozdem ab.
Für unsere Fremdschlüssel sollte das kein Problem sein, die sind i.d.R.
20, maximal 50 Zeichen lang.
Post by Günther Bach
Meine Trigger lösen andere Probleme als Du hast, daher spielt der
Inhalt (in meinen Augen) keine Rolle.
Na ja, das Problem, das ich lösen wollte, war schon irgendwie mit dabei.
Nur, dass wir halt bisher mit AFTER-Triggern gearbeitet haben und da kann
ich den alten Wert eben nur noch aus der deleted-Tabelle ermitteln.
Post by Günther Bach
Ich dachte, Du wolltest nur wissen, wie man in Triggern Schleifen
"programmiert", um alle von einer Änderung betroffenen Datensätze zu
erfassen. Und das tun meine Beispiele.
Wollte ich ja auch, weil ich dachte, dass das eine mögliche Lösung sein
könnte. Was mir aber in den anderen Postings wiederlegt wurde, da ich egal
wie rum (INSTEAD OF oder AFTER) keine eindeutige Zuordnung von neuem und
alten Wert herstellen kann.


Mit freundlichen Grüßen
Daniel Barisch
Elmar Boye
2005-09-28 19:01:41 UTC
Permalink
Hallo Günther,
Post by Günther Bach
Post by Günther Bach
Das war ja auch ein UPDATE-Trigger (bzw. INSTEAD OF UPDATE, weil der
dämliche SQL-Server massive Probleme mit TEXT-Feldern hat),
Aber auch dann kann man sich nicht auf die Trigger verlassen. Irgendwo
(afaik bei einigen 100 kB) schneiden einige SQL-Server-Funktionen den
Inhalt von Textfeldern trozdem ab.
Blödsinnn, siehe SET TEXTSIZE.
Post by Günther Bach
Meine Trigger lösen andere Probleme als Du hast, daher spielt der
Inhalt (in meinen Augen) keine Rolle.
Nach oben kommt der Verdacht, die sind hausgemacht.

Gruss
Elmar
Hans Preuer
2005-09-28 19:22:45 UTC
Permalink
Hallo Daniel,

Vielleicht habe ich jetzt auch ein "Brett vorm Kopf", aber ich habe den
kompletten langen Thread gelesen und soweit ich mitbekommen habe, willst du
ja eigentlich nur eine referentielle Integritätsweitergabe des
Masterschlüssels an die Detail-Datensätze. Warum machst du da im
EnterpriseManager nicht einfach ein Diagramm wie in MS Access, holst Dir die
beteiligten Tabellen herein und zeichnest eine Beziehung und gibst dort in
den Eigenschaften die ganzen Felder etc. wie in Access an und hackelst dann
einfach "Beziehung für INSERT und UPDATE Anweisung erzwingen" bzw.
"Verknüpfte Felder mit CASCADE aktualisieren" und "Verknüpfte Datensätze mit
CASCADE löschen" an, wie in Access ???? Du brauchst da ja eigentlich gar
keine Trigger.

Wie gesagt: Vielleicht verstehe ich Dich auch falsch??

Tschau
Hans
Post by
Hallo NG!
In einer relationalen Datenbank soll es ja des öfteren 1:n-Beziehungen
geben...
Da der MS SQL Server Beziehungen aber nicht allzu toll unterstützt, haben
wir in unserer Datenbank die Integritätsprüfung über Trigger realisiert. Das
funktioniert ganz gut, solange nur ein Datensatz geändert/gelöscht wird.
Werden aber mehrere Datensätze auf einmal geändert ("UPDATE Tabelle
SET Feld = Replace(Feld, 'abc', 'xyz') WHERE Feld IN (...)"),
dann wirkt der Trigger anscheinend nur für einen der geänderten Datensätze.
Enthält die "deleted" - Tabelle immer nur den letzten oder alle geänderten
Datensätze, die man dann in einer Schleife durchlaufen kann? Wenn ja wie?
Ich habe bisher immer nur Beispiele gefunden, die davon ausgehen, dass nur
ein Datensatz betroffen ist.
Mit freundlichen Grüßen
Daniel Barisch
2005-09-29 06:21:49 UTC
Permalink
Hallo Hans!
Post by Hans Preuer
Vielleicht habe ich jetzt auch ein "Brett vorm Kopf", aber ich habe den
kompletten langen Thread gelesen und soweit ich mitbekommen habe, willst
du ja eigentlich nur eine referentielle Integritätsweitergabe des
Masterschlüssels an die Detail-Datensätze.
Nö, kein Brett. Das hast Du völlig richtig verstanden.
Post by Hans Preuer
Warum machst du da im EnterpriseManager nicht einfach ein Diagramm wie in
MS Access, holst Dir die beteiligten Tabellen herein und zeichnest eine
Beziehung und gibst dort in den Eigenschaften die ganzen Felder etc. wie
in Access an und hackelst dann einfach "Beziehung für INSERT und UPDATE
Anweisung erzwingen" bzw. "Verknüpfte Felder mit CASCADE aktualisieren"
und "Verknüpfte Datensätze mit CASCADE löschen" an, wie in Access ???? Du
brauchst da ja eigentlich gar keine Trigger.
Weil wir keine Lust haben, das bei allen unseren hoffentlich bald mehreren
Millionen Kunden per Hand einzurichten. Von der dabei auftretenden
statistischen Fehlerquote mal ganz zu schweigen. Deshalb erzeugen wir das
alles per SQL in einer Art Setup.

Außerdem hat mir jemand gesagt, im SQL Server würden Beziehungen nur über
jeweils ein Feld herstellbar sein. Aber wie ich schon in einem anderen
Posting geschrieben habe, werd ich das nochmal prüfen müssen. Auf diese
Aussage habe ich mich einfach verlassen und als ich die Sache in die Hand
bekommen habe, war die Lösung über Trigger schon mehr oder weniger
beschlossen.
Post by Hans Preuer
Wie gesagt: Vielleicht verstehe ich Dich auch falsch??
Wie gesagt: Nö.


Mit freundlichen Grüßen
Daniel Barisch
Loading...