Autor Beitrag
SchwarzesShaaf666
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 28

Win XP
D6 Pers
BeitragVerfasst: Do 14.07.05 14:50 
Ich kenne mich mit Triggern überhaupt nicht aus. Möchte aber folgendes Problem mit einem Trigger lösen:

Wenn in einer Tabelle "Raum" ein Datensatz gelöscht wird, soll vor dem löschen (BEFORE DELETE) eine andere Tabelle überprüft werden, ob Datensätze vorhanden sind, die auf Raum verweisen. Falls es der Fall sein sollte soll das Löschen verhindert werden.

Wäre schön, wenn mir da jemand helfen könnte. Oder zumindest eine Quelle im Internet posten könnte, die mir weiterhilft!
Udontknow
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 2596

Win7
D2006 WIN32, .NET (C#)
BeitragVerfasst: Fr 15.07.05 12:13 
Hallo!

Erstelle besser einen Fremdschlüssel (Foreign key) für soetwas, einen Trigger braucht man in diesem Falle (noch) nicht.

Cu,
Udontknow
SchwarzesShaaf666 Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 28

Win XP
D6 Pers
BeitragVerfasst: Fr 15.07.05 13:07 
Das Problem an diesen Tabellen ist, daß der Raum in der anderen Tabelle kein Primary Key ist und auch nicht zu einem gemacht werden kann. Ergo: kein Foreign Key möglich (oder irre ich mich da?)
Udontknow
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 2596

Win7
D2006 WIN32, .NET (C#)
BeitragVerfasst: Fr 15.07.05 14:53 
Ich meine, mich erinnern zu können, daß das referenzierte Feld nicht unbedingt der Primärschlüssel sein muss, wohl aber unique...

Cu,
Udontknow
Lemmy
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
Beiträge: 792
Erhaltene Danke: 49

Windows 7 / 10; CentOS 7; LinuxMint
Delphi 7-XE10.1, VS 2015
BeitragVerfasst: Fr 15.07.05 21:01 
Hi,

ich würde das über ne Stored Procedure machen:

ausblenden SQL-Anweisung
1:
2:
3:
4:
5:
6:
7:
8:
CREATE PROCEDURE DeleteIrgendwas (ID Integer)
AS
DECLARE VARIABLE Anzahl Integer;
BEGIN
  Select count (ID) from Rechnung where Adresse_ID=:ID INTO Anzahl;
  IF (Anzahl=0) then
    DELETE from Adresse where ID=:ID;
END


Ich denke Umschreiben sollte kein Problem sein, wenn doch einfach nochmal melden...

Grüße
Lemmy

Moderiert von user profile iconraziel: Code- durch SQL-Tags ersetzt
Udontknow
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 2596

Win7
D2006 WIN32, .NET (C#)
BeitragVerfasst: Sa 16.07.05 17:30 
Ja, die SP muss doch aber dann auch ausgeführt werden, und das geht dann doch wieder über einen Trigger, wenn man es nicht clientseitig machen will (was ja auch nicht so elegant wäre).

Cu,
Udontknow
hansa
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 3079
Erhaltene Danke: 9



BeitragVerfasst: So 17.07.05 14:05 
Udontknow, über Elaganz läßt sich streiten. Aber Lemmy's Vorschlag ist schon richtig so. Alles in die DB zu verlagern, das kann auch nach hinten los gehen. Aber egal.

Was ich noch sagen will : in dem Zusammenhang sollte man sich mal CASCADE ansehen. Das geht zwar jetzt in die umgekehrte Richtung. Dabei gehts darum, daß auch die per foreign Key verknüpften Records gelöscht werden. Mir kommt es so vor, daß das nur seltenst benutzt wird.

_________________
Gruß
Hansa
Udontknow
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 2596

Win7
D2006 WIN32, .NET (C#)
BeitragVerfasst: Mo 18.07.05 07:53 
Hallo Hansa!

user profile iconhansa hat folgendes geschrieben:
Udontknow, über Elaganz läßt sich streiten. Aber Lemmy's Vorschlag ist schon richtig so. Alles in die DB zu verlagern, das kann auch nach hinten los gehen.


Was kann denn nicht nach hinten los gehen? Was speziell kann nach hinten losgehen, wenn man dies in die DB verlagert? Bei richtiger Implementierung unter richtigen Vorgaben ist das doch in Ordnung, und der Fragesteller wollte es in der DB machen... :nixweiss:


user profile iconhansa hat folgendes geschrieben:

Was ich noch sagen will : in dem Zusammenhang sollte man sich mal CASCADE ansehen. Das geht zwar jetzt in die umgekehrte Richtung. Dabei gehts darum, daß auch die per foreign Key verknüpften Records gelöscht werden. Mir kommt es so vor, daß das nur seltenst benutzt wird.


CASCADE ist sogar bei mir eigentlich an der Tagesordnung, kaum ein FK, der nicht "ON DELETE CASCADE" beinhaltet. Es ist halt unglaublich praktisch, sich nicht selber um die Hierarchien und Abhängigkeiten kümmern zu müssen, wenn man einen Datensatz mit n Detaildatensätzen, die wiederum in 5 Tabellen m Datensätze "besitzen", löschen möchte.

Die Vorgabe war ja nun ein Abbruch bei Vorhandensein von Detaildaten. War das dann "ON DELETE NOACTION"? Ich hab´s vergessen... :wink:

Cu,
Udontknow
Lemmy
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
Beiträge: 792
Erhaltene Danke: 49

Windows 7 / 10; CentOS 7; LinuxMint
Delphi 7-XE10.1, VS 2015
BeitragVerfasst: Mo 18.07.05 08:12 
Hi,

also ob ich ein

ausblenden Delphi-Quelltext
1:
Delete from Adresse where ID=19;					


oder ein

ausblenden Delphi-Quelltext
1:
Execude Procedure DeleteRechnung(19);					


aufrufe spielt jetzt doch überhautp keine Rolle, oder? Ich persönlich arbeite nicht gerne mit Triggern und mit Foreign Keys ebenfalls nicht, mit kaskadierenden schon zwei mal nicht. Sicherlich sparen die ne Menge Tipparbeit und man kann sich auf die Funktionalität sicher verlassen, doch es hat sich gezeigt, dass ich mit manuellen Indizes auf bestimmte Spalten besser fahre. Dieses Wissen habe ich mir aber hautpsächlich angelesen, wenn ich das Teil finde werde ich nen Link posten. Diese Aussage (Arbeit ohne Foreign Keys) bezieht sich ausschließlich auf IB/FB.

Lemmy
hansa
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 3079
Erhaltene Danke: 9



BeitragVerfasst: Mo 18.07.05 09:20 
Udontknow, ich meine, daß man es nicht übertreiben sollte mit "Verlagern in die Datenbank" !

Lemmy, das da verwundert mich etwas. Keine Foreign Keys ? :shock:

expertanswercenter.t...3_gci1054399,00.html

Das deckt sich voll und ganz mit meinen Erfahrungen. Der verwendet sogar das Wort Pikosekunden. 10^-12 Sek. Ich bevorzuge immer Nanosekunden 10^-9. :lol: Und diese Zeitspannen sind es allemal nicht Wert, die Konsistenz der DB aufs Spiel zu setzen. 8)

_________________
Gruß
Hansa
Udontknow
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 2596

Win7
D2006 WIN32, .NET (C#)
BeitragVerfasst: Mo 18.07.05 09:21 
Tjaaa... Ehrlich gesagt, habe ich da in der Praxis sehr viel bessere Erfahrungen gehabt, wenn ich soviel wie möglich der Logik auf die DB ausgelagert habe. Die Datenkonsistenz/Integrität durch clientseitige SQL und rein-logische Fremdschlüssel (das meinst du doch mit "manuellen Indizes", oder? Ein Index ist ja eigentlich noch was anderes bei IB/FB) zu gewährleisten, ist äusserst problematisch.

Was passiert bei Programmabstürzen oder eben Fehlern im Programm? Was passiert bei Multi-User-Zugriff (der eine löscht Hauptdatensatz, der andere fügt gerade Details ein)? Um all diese Problematiken musst du dich nicht kümmern, wenn du FKs implementierst. Der Benutzer, der Detaildaten zu einem bereits gelöschten Datensatz einfügen will, bekommt automatisch beim Posten eine Exception. Bei rein logischen Schlüsseln musst du immer wieder selbst prüfen.

Was soetwas angeht, da vertraue ich lieber dem IB-Code, der sich millionenfach bewährt hat, als meine eigene (häufig Un-)Logik anzuwenden...

@ Hansa: Jepp, der Artikel trifft´s genau! :o

Cu,
Udontknow
hansa
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 3079
Erhaltene Danke: 9



BeitragVerfasst: Mo 18.07.05 09:49 
Schöner Artikel, was ? :mrgreen: Der trifft den Nagel wirklich auf den Kopf. Noch ein Tip am Rande : man lade sich mal die 45-Tage Trial-Vollversion von IBExpert runter. Nicht die freie Personal ! Und dann mal fleißig kaskadierte Tables löschen. Es wird dann angezeigt was alles gelöscht wird. Manch einer wird sich da wundern. Inkl. mir selber. Ich hätte mit Sicherheit eine (relativ unwichtige) Table vergessen. Die DB hat aber daran gedacht. 8)

_________________
Gruß
Hansa
Lemmy
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
Beiträge: 792
Erhaltene Danke: 49

Windows 7 / 10; CentOS 7; LinuxMint
Delphi 7-XE10.1, VS 2015
BeitragVerfasst: Mo 18.07.05 12:58 
Hi

@Udontknow: Ich gebe Dir vollkommen recht, ABER: Bei IB/FB habe ich Recht! Ein Multiuser-Zugriff auf Master-Detaildatensätze spielen keine Rolle, ebenso ein Programmabsturtz, denn IB/FB habe eine hervorragende Transaktionsverwaltung mit Multi-Generationen-Architektur. Somit kann da nie was schief gehen!

Foreign-Keys in IB/FB haben in erster Linie wirklich nur den Sinn einen Index auf eine Spalte zu erzeugen. Klar laufen bei Foreign-Keys noch ein paar weitere Prüfungen ab. Der Hauptgrund allerdings auf Foreign-Keys (im allgemeinen auf alle automatisch erzeugte Schlüssel, also auch Primary-Keys) zu verzichten ist, dass IB/FB nicht erlauben, diesen Schlüsseln einen Namen zu geben! Wenn also beim User ne Fehlermeldung kommt in dem der Index mit "PK123" oder mit "PKAdresse" benannt wird, macht beim Support einen großen Unterschied! Wenn ich mich recht entsinne, können die Schlüssel zudem bei jedem Backup/Restore-Zyklus anders benannt werden (je nachdem wann sie erzeugt werden), was das Problem also noch verschlimmert!

Desweiteren lassen manuell erzeugte Indizes auch weitere Einstellungen zu wie asc und desc,.... und sie lassen sich bei einer großen Insert/Delete/Update-Aktion gezielt deaktivieren, was z.B. den Import von Adressdaten unglaublich beschleunigt!

Nach all dem theoretischen Geschwafel: Ich habe ein Auftragsmanagementprogramm entwickelt (ca. 2,5 Mannjahre) und die Applikation als ich diese auf FB umgesetzt habe bei den meisten Dingen auf Foreign-Keys verzichtet (Auftragsverwaltung, Kundenverwaltung, Zeiterfassung,..). Die Applikation ist seit ca. 3 Jahren voll im Einsatz. Ich habe bis heute noch keine Probleme mit fehlenden oder falschen Relationen (wenn man mal von den Problemen und Fehlern mitten in der Entwicklung absieht). Die Relationen habe ich i.d.R. mittels StoredProcedures abgebildet und bin damit immer gut gefahren.


Aber nochmal der Hinweis von meinem letzten Posting: Das hier gesagte trifft wirklich nur auf IB/FB zu!!


Lemmy
Lemmy
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
Beiträge: 792
Erhaltene Danke: 49

Windows 7 / 10; CentOS 7; LinuxMint
Delphi 7-XE10.1, VS 2015
BeitragVerfasst: Mo 18.07.05 13:12 
Nachtrag:

Ich habe den Artikel gefunden:

bdn.borland.com/arti...9,00.html#Subtopic10

Als weiteren wichtigen Punkt wird folgendes aufgeführt (ich bin zu faul zum übersetzen, aber mit ein paar Englischkenntnissen ist das Verständnis kein Problem):


[zitat]

Foreign keys are a different story. Lets assume you have a table with a field called "Address_State" in it and you want to limit what is accepted in that field to one of the 50 States, so you create a foreign key to a table called States. When you make the foreign key declaration, InterBase will create an index on the "Address_State" field. The purpose of this index is for when you try to delete a row from the States table. It will allow InterBase to quickly check the "Address_State" field to ensure the value contained in the States table record that you are trying to delete, is not present in the Address_state field.

The performance problem is with the in index that is created on the "Address_State" field. If you have 1,000,000 records in your table and there 50 states then there are roughly 20,000 records per state in the "Address_State" field index, making it a very very poor index. If the InterBase optimizer gets a hold of it this index, there can be problems.

One site that had this problem was running a report that never finished. An examination of the problem revealed that one column had 95,000 rows with the number 3 in it and 5,000 nulls. There was an index on this field created by a foreign key. The InterBase optimizer found this index and the index caused the optimize to solve the problem backwards. The result was an report/query that could not finish in 10 hours. By dropping the foreign key and its index and replacing it with triggers, the optimizer solve the problem in a couple of minutes and the reports came out. [/zitat]
Udontknow
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 2596

Win7
D2006 WIN32, .NET (C#)
BeitragVerfasst: Mo 18.07.05 13:13 
Was nützen dir Transaktionen?

Der eine Benutzer holt sich die Stammdaten, wählt einen Datensatz aus und macht sich daran, einen Detaildatensatz einzufügen (was er noch nicht komplett getan hat). Während dessen geht ein anderer Benutzer her und löscht den Hauptdatensatz weg. Kurz darauf posted der erste User seinen Detail-Datensatz, schliesslich bekommt er nicht on-the-fly mit, daß der Master nicht mehr existiert. Da hilft dir keine Multi-Generationen-Architektur. Schon hast du einen Detaildatensatz ohne Master, und daß nur, weil du keinen FK angelegt hast.

Mein Gedächtnis mag mich ja jetzt täuschen, aber ich meine mich zu erinnern, daß sich ein Foreign-Key sehr wohl benamen ließ, und der wird im Falle einer Integritätsverletzung dann auch so ausgegeben ("violation on foreign key PERSON_GRUPPE...").

Nachtrag: Ganz im Ernst, solche Probleme hat man seltenst, ich habe sie trotz ähnlicher Situationen noch nie so erlebt. Der Artikel ist uralt (2001), der Optimizer existiert in dieser Form gar nicht mehr. Die Probleme wurden höchstwahrscheinlich schon vor Jahren behoben. Ganz davon abgesehen, daß der Artikel sich auf Indizes auf Schlüsselfelder im Allgemeinen bezieht, die ja wohl ihre Berechtigung ohne Zweifel haben und die du doch wohl in deinem Projekt auch angelegt hast. :wink:

Cu,
Udontknow


Zuletzt bearbeitet von Udontknow am Mo 18.07.05 14:06, insgesamt 1-mal bearbeitet
CenBells
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 1547

Win 7
Delphi XE5 Pro
BeitragVerfasst: Mo 18.07.05 13:45 
Hi,

nur ganz am Rande... Ich kann bestätigen, daß man einem FK/PK einen Namen geben kann. Von daher gibt es da kein Problem mehr mit den Fehlermeldungen.

Gruß
Ken

_________________
Eine Klasse beschreibt die Struktur und das Verhalten einer Menge gleichartiger Objekte.
SchwarzesShaaf666 Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 28

Win XP
D6 Pers
BeitragVerfasst: Mo 05.12.05 09:28 
Vielleicht melde ich mich etwas spät aber das ist immernoch besser als nie... ;-)

Vielen Dank Lammy, Deine Prozedur hat geholfen!!!
alex517
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 60


D7Ent, FB, FIBPlus
BeitragVerfasst: Mo 05.12.05 11:51 
Hallo alle zusammen,

ich denke Foreign-Keys sollten immer dann eingesetzt werden wenn die Integrität der
Master-/Detail-Daten sichergestellt werden muß. (z.B. Rechnung - Rechungsposten)
Es kann nun mal kein Rechungsposten ohne Rechnung existieren. Und wenn eine Rechung gelöscht werden soll
dann auch die Rechnungsposten. Hier bietet sich das 'CASCADE' an.

Soll das Löschen des Mastersatzes trotz vorhandener Details zulässig sein, dann setzt man die
Löschregel auf 'SET NULL' oder 'SET DEFAULT'.

Ist das Löschen der Mastersatzes zu unterbinden ist die Löschregel 'NO ACTION'.

Der Foreign-Key im Detaildatensatz brauch/sollte nicht identisch mit dem Primary-Key sein.
Bei mir hat JEDE Tabelle einen Primary-Key mit dem Namen "ID".
Links auf andere Tabellen haben dem Name "<Tabelle>_ID". Diese Felder bilden dann auch den Foreign-Key.

Sollen keine Foreign-Keys eingesetzt werden, kann das Löschen eines Masterdatensatzes auch
über einen Trigger unter Verwendung einer EXCEPTION unterbunden werden.
Damit erhält man auch die passende Fehlermeldung.

ausblenden SQL-Anweisung
1:
2:
3:
4:
5:
6:
7:
CREATE TRIGGER MASTERTAB_BD0 FOR MASTERTAB
ACTIVE BEFORE DELETE POSITION 0
AS
begin
  if (EXISTS (SELECT * FROM DETAIL_TAB D WHERE D.MASTER_ID = OLD.ID)) then
    EXCEPTION EX_NICHT_LOESCHBAR 'Abhängige Daten in Tabelle XYZ vorhanden!';
end

oder mit Lemmys SP aber ohne Fehlermeldung.

alex