| Autor |
Beitrag |
hansa
      
Beiträge: 3079
Erhaltene Danke: 9
|
Verfasst: Di 19.08.03 19:44
Hi,
UGrohne und auch Lemmy haben mir gesagt, ich solle möglichst viele Stored Procedures benutzen. Mir geht es um ein Eingabeformular, wobei 5 Tables aktualisiert werden. Aber da werden doch gar keine Daten abgerufen, sondern eingefügt ? Bzw. wird ein Teil gelesen, das wichtigste ist aber das wegschreiben. Wie soll ich das am besten machen ? Das ganze soll auf einer Form passieren.
_________________ Gruß
Hansa
|
|
UGrohne
      

Beiträge: 5502
Erhaltene Danke: 220
Windows 8 , Server 2012
D7 Pro, VS.NET 2012 (C#)
|
Verfasst: Di 19.08.03 22:50
Du erstellst einfach eine Stored Procedure à la:
Quelltext 1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13:
| CREATE PROCEDURE update ( feld1 INTEGER, feld2 VARCHAR(20), .... ) AS BEGIN id1=gen_id(gen1,1); INSERT INTO tabelle1 VALUES(feld1,....); .... EXIT; END |
Diese rufst Du dann einfach über
Quelltext 1:
| EXECUTE PROCEDURE update(2,'feldwert2',.....); |
auf und das wars. Du kannst da soviel reinpacken, wie Du willst.
Du kannst auch mehrere Procedures nutzen und diese sich gegenseitig aufrufen lassen, auch kein Problem.
Die obige ist eine Executable Procedure, im Gegensatz zu Select-Prozeduren, die Daten zurückgeben. Da kommt vor dem AS noch der RETURNS-Block.
Auf der Form würde ich Dir vorschlagen, Bereiche zu definieren, die Tabellenweise gegliedert sind, z.B. (von meinem aktuellen projekt) eine Firmenadresse ist ein Block und der andere sind die Ansprechpartner. Diese solltest Du getrennt aktualisieren, damit Du, wenn sich beim einen nichts ändert, diesen Block nicht auch noch unnötig updatest.
Noch Fragen? Fragen!
|
|
hansa 
      
Beiträge: 3079
Erhaltene Danke: 9
|
Verfasst: Mi 20.08.03 10:28
Habe jetzt mal eine stored procedure gebaut: Alle Rechnungsbeträge eines Jahres werden mit Hilfe einer "Select-Procedure" addiert etc.:
Quelltext 1: 2: 3: 4: 5: 6:
| BEGIN SELECT SUM(UMSATZMWST2), AVG (UMSATZMWST2), MAX (UMSATZMWST2) FROM RECKOPF8 WHERE EXTRACT(YEAR FROM RECHNDATUM) = :RECHNJAHR INTO :tot_budget, :avg_budget, : max_budget; SUSPEND; END |
Habe mich natürlich an entsprechenden Beispielen orientiert, funktionieren tut es aber mit meinen Originaldaten. *stolz* Jetzt stellt sich aber eine kurze Zwischenfrage : Ich muß eine leere DB ausliefern. Ist die Procedure da drin ?
Und die Hauptfrage @UGrohne: Was ist mit dem Generator in Deinem Beispiel. Benutzt Du keinen BI-Trigger ? Und gleich die nächste: Wie unterscheide ich am besten, ob ein Datensatz mit Insert neu eingefügt werden muß, oder ein vorhandener geupdatet werden soll  Das müßte die entsprechende SP wohl wissen.
_________________ Gruß
Hansa
|
|
Lemmy
      
Beiträge: 792
Erhaltene Danke: 49
Windows 7 / 10; CentOS 7; LinuxMint
Delphi 7-XE10.1, VS 2015
|
Verfasst: Mi 20.08.03 10:41
Hi,
ich bin zwar nicht UGrohne aber antworte trotzdem...
| hansa hat folgendes geschrieben: | | Ich muß eine leere DB ausliefern. Ist die Procedure da drin ? |
Nur wenn Du sie mit Create Procedure erzeugt hast *gg*
| hansa hat folgendes geschrieben: |
Und die Hauptfrage @UGrohne: Was ist mit dem Generator in Deinem Beispiel. Benutzt Du keinen BI-Trigger ? |
Ich benutze auch keine Trigger, sind mir nicht gut genug. Wenn ich in meiner Client-Anwendung die ID des eingefügten Datensatzes kennen muss, damit ich ihn nach dem einfügen gleich wieder in der Maske anzeigen lassen kann, dann bringt mir der Trigger rein gar nichts!! In einer SP kann ich die ID des eingefügten Datensatzes zurückgeben, oder ich verwende einfach die Generator-Eigenschaft der DataSet.
| hansa hat folgendes geschrieben: | Und gleich die nächste: Wie unterscheide ich am besten, ob ein Datensatz mit Insert neu eingefügt werden muß, oder ein vorhandener geupdatet werden soll Das müßte die entsprechende SP wohl wissen. |
Lass den Datensatz von der SP doch einfach suchen..... Bei Deinem Bsp.: Willst Du die berechneten Werte in einer Tabelle GesamtRechnung abspeichern, dann lass einfach nach dem Jahr suchen:
Quelltext 1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11:
| DECLARE VARIABLE Anzahl INTEGER; BEGIN SELECT Count(*) From GesamtRechnung where EXTRACT(YEAR FROM RECHNDATUM) = :RECHNJAHR INTO :Anzahl; IF (:Anzahl=0) then BEGIN INSERT INTO.... END ELSE BEGIN UPDATE GesamtRechnung..... END; |
So sollte es ungefähr hinhauen....
GRüße
Lemmy
|
|
hansa 
      
Beiträge: 3079
Erhaltene Danke: 9
|
Verfasst: Mi 20.08.03 11:26
Wie, Lemmy ? Nix Urlaub  Wie ich sehe, muß ich mich wieder etwas mehr mit SQL beschäftigen. Habe mir deshalb gestern mal ein Buch darüber gekauft.  Das mit :Anzahl kommt mir etwas kompliziert vor. *grübel* Aber mir fällt auch nichts besseres ein. Das Beispiel ist auch nicht so gut gewählt. Was ist in folgendem Fall zu tun: neuer Artikel, Lagerbestand deshalb auch nicht vorhanden. Jetzt könnte ich ja 2 Dinge tun: 1. leeren Datensatz Lagerbestand usw. anlegen, sofern ein neuer Artikel angelegt wird, dann wäre die Unterscheidung Insert/Update überflüssig 2. Für solche Fälle eine stored procedure, so ähnlich wie Lemmy das gemacht hat. Dann bräuchte ich für jede Tabelle wahrscheinlich alleine dafür eine SP.
Dies wiederum würde erklären, warum andere so viele SP brauchen. Das hat mich sowieso schon gewundert. Stop, es gibt noch eine Variante: In Delphi kann ich doch Dataset.IsEmpty
überprüfen. Also in diesem Fall jetzt SELECT * FROM LAGERBESTAND WHERE ID_ART = ???
Ist die Datenmenge leer dann eben ein insert. Wobei wir da wieder bei der Grundsatzfrage wären, ob die DB die Arbeit macht oder mein Programm. Aber, wie man sieht, da muß noch etwas Licht ins Dunkel.
@Lemmy: das mit dem Trigger verstehe ich auch nicht richtig, was Du da meinst. Mit einem BI-Trigger erhalte ich doch sofort eine ID?
_________________ Gruß
Hansa
|
|
Lemmy
      
Beiträge: 792
Erhaltene Danke: 49
Windows 7 / 10; CentOS 7; LinuxMint
Delphi 7-XE10.1, VS 2015
|
Verfasst: Mi 20.08.03 12:00
| hansa hat folgendes geschrieben: | Wie, Lemmy ? Nix Urlaub |
Was, Hansa?? Was ist Urlaub???
| hansa hat folgendes geschrieben: |
Was ist in folgendem Fall zu tun: neuer Artikel, Lagerbestand deshalb auch nicht vorhanden. Jetzt könnte ich ja 2 Dinge tun: 1. leeren Datensatz Lagerbestand usw. anlegen, sofern ein neuer Artikel angelegt wird, dann wäre die Unterscheidung Insert/Update überflüssig 2. Für solche Fälle eine stored procedure, so ähnlich wie Lemmy das gemacht hat. Dann bräuchte ich für jede Tabelle wahrscheinlich alleine dafür eine SP.
|
Ohne Deine DB-Struktur zu kennen kann ich da gerade recht wenig dazu beitragen....
| hansa hat folgendes geschrieben: |
Dies wiederum würde erklären, warum andere so viele SP brauchen. Das hat mich sowieso schon gewundert. Stop, es gibt noch eine Variante: In Delphi kann ich doch Dataset.IsEmpty
überprüfen. Also in diesem Fall jetzt SELECT * FROM LAGERBESTAND WHERE ID_ART = ???
Ist die Datenmenge leer dann eben ein insert. Wobei wir da wieder bei der Grundsatzfrage wären, ob die DB die Arbeit macht oder mein Programm. Aber, wie man sieht, da muß noch etwas Licht ins Dunkel.
|
Klar, Du könntest auch den Anwendern Schieferplatten, nen Hammer und nen Meisel in die Hand drücken, dann werden die nie Probleme mit Windows haben....
Im Ernst: Wenn Du ne halbwegs schnelle und wartbare Applikation haben willst, sind StoredProcedures unverzichtbar. Auch ich habe am Anfang ohne die SP gearbeitet, aber mich nach und nach ihnen genähert und immer mehr gemacht. Versuche doch erst mal Dein Problem in der Client-Applikation zu lösen. WEnn Du das geschafft hast, kannst Du über ne Implementierung als SP nachdenken. SP's ganz theoretisch durchzudenken macht IMHO wenig Sinn.
| hansa hat folgendes geschrieben: |
@Lemmy: das mit dem Trigger verstehe ich auch nicht richtig, was Du da meinst. Mit einem BI-Trigger erhalte ich doch sofort eine ID? |
Wie verwendest DU den Trigger?? Doch so, dass Du nen Insert-Trigger erzeugst, der den Wert der ID abfragt, ist der NULL wird eine neue ID mit dem Generator erzeugt und zugewiesen. In diesem Zustand weiß aber die Client-Applikation nichts von dem Wert der ID! Wenn Du also die gerade eingefügten Datensatz nach dem Einfügen gleich anzeigen lassen willst, musst Du den irgendwie in der Datenbank wiederfinden. Genau da liegt das Problem! Wie willst Du den Datensatz eindeutig identifizieren???
Ich dagegen verwende in diesem Fall keinen Trigger sondern eine Insert-SP bzw. die Eigenschaft Generator der IBDataSet. Damit erhalte ich immer die ID des eingefügten DS zurück und kann diesen eindeutig identifizieren....
Grüße
Lemmy
|
|
hansa 
      
Beiträge: 3079
Erhaltene Danke: 9
|
Verfasst: Mi 20.08.03 12:13
Lemmy, meinst Du etwa, ich soll meine ganzen Trigger wegschmeißen ?  Habe im Moment 27 ? Tables und für jede einen Trigger. Was macht denn eine Insert-SP anders, als ein Trigger  Soll ich das wieder umbauen ?
_________________ Gruß
Hansa
|
|
UGrohne
      

Beiträge: 5502
Erhaltene Danke: 220
Windows 8 , Server 2012
D7 Pro, VS.NET 2012 (C#)
|
Verfasst: Mi 20.08.03 12:47
Mit der SP hast Du viel mehr Kontrollmöglichkeiten. Der Trigger von Dir wird ja nur aktiv, wenn Du einen Datensatz einfügst, dann generiert er eine neue ID und weist diese zu. Aber wenn Du diese ID in Deinem Prog brauchst, musst Du den Datensatz mit einer neuen Abfrage erst wieder suchen. Mit der SP kannst Du die ID wie der Trigger erzeugen und diese dann zurückgeben, das war der erste Grund für mich eine INSERT-SP zu schreiben.
|
|
Lemmy
      
Beiträge: 792
Erhaltene Danke: 49
Windows 7 / 10; CentOS 7; LinuxMint
Delphi 7-XE10.1, VS 2015
|
Verfasst: Mi 20.08.03 12:53
Hi Hansa,
ganz einfach: Die Insert-SP gibt die ID zurück, d.h. ich weiß im Client den Wert der ID. Das funktioniert im Trigger nicht...
Wenn Du diese Möglichkeit (Anzeige des gerade eingegebenen DS) nicht brauchst, dann musst Du auch nicht zwangsläufig was umstellen.... Kommt halt immer darauf an...
Grüße
Lemmy
|
|
hansa 
      
Beiträge: 3079
Erhaltene Danke: 9
|
Verfasst: Mi 20.08.03 13:24
Ihr wißt doch, daß ich dumm bin.  Also müßt ihr mir das erklären.  Das gilt doch wohl nur für neue Datensätze ? Meint Ihr, ich solle im Fall der Fälle die ID als Output-Parameter irgendwie übergeben oder wie ? Und was passiert in einem Netztwerk, wenn ich das ganze mit dem Trigger mache ? Dann merkt doch nur das Programm nichts davon, oder die anderen WS auch nicht 
_________________ Gruß
Hansa
|
|
Lemmy
      
Beiträge: 792
Erhaltene Danke: 49
Windows 7 / 10; CentOS 7; LinuxMint
Delphi 7-XE10.1, VS 2015
|
Verfasst: Mi 20.08.03 14:16
Nein Hansa, du bist nicht dumm....
Klar gilt das nur für neue Datensätze, Dein Trigger doch auch und ja, die neue ID wird bei einer Insert-Sp als Output Parameter zurückgegeben. Es spielt dabei keine Rolle, ob es sich um ne EinzelplatzAppl oder NetzwerkAppl handelt.
|
|
hansa 
      
Beiträge: 3079
Erhaltene Danke: 9
|
Verfasst: Mi 20.08.03 17:22
Moment. Feuere ich den Triger ab, ist dann der Datensatz nicht in der DB drin ? Ist es nicht eher so, daß ich den an der Workstation, wo das passiert nicht mitkriege, die anderen aber schon 
_________________ Gruß
Hansa
|
|
Lemmy
      
Beiträge: 792
Erhaltene Danke: 49
Windows 7 / 10; CentOS 7; LinuxMint
Delphi 7-XE10.1, VS 2015
|
Verfasst: Do 21.08.03 07:32
Guten Morgen Hansa,
es geht hier rein um die ID. Wenn Dein Insert-Trigger feuert ist der Datensatz in der DB drin, wie soll denn der Trigger sonst feuern??? Das Prob ist dass der Trigger die ID nicht zurückgeben kann, eine SP schon. Es kommt aber immer darauf an, was Du machst. Wenn es nicht wichtig ist, die ID im Clientprogramm zu kennen, brauchst Du dir darüber auch keine Gedanken machen....
GRüße
Lemmy
P.S.: Die PN schaue ich mir später genauer an...
|
|
|