Autor |
Beitrag |
OlliWausD
      
Beiträge: 212
Win 2000/XP
Delphi 5 Professional - Interbase/Firebird
|
Verfasst: Do 23.09.04 18:26
hi jungs, ich mal ne wichtige frage an euch:
ist es möglich eine Stored Procedure (welche ja normalerweise in der DB geschreiben werden) zur Laufzeit zu erstellen ??
Mit dem Prinzip, dass man, sobald man eine benötigt, diese erstellt, anschließend eine Selectabfrage drüber bügelt und diese nach beendigung der Aufgabe wieder löscht.
Wäre von großen Nutzen für mich.
mfg
OlliW
ps.: ich benutze Firebird 1.0
_________________ Take it easy
|
|
CenBells
      
Beiträge: 1547
Win 7
Delphi XE5 Pro
|
Verfasst: Do 23.09.04 20:12
hallo,
klar ist das möglich, warum auch nicht? Nimm dazu die entsprechende Komponente (Interbase -> IBSQL, o.ä) und führe die entsprechenden Statements aus.
Gruß
Ken
_________________ Eine Klasse beschreibt die Struktur und das Verhalten einer Menge gleichartiger Objekte.
|
|
Udontknow
      
Beiträge: 2596
Win7
D2006 WIN32, .NET (C#)
|
Verfasst: Do 23.09.04 22:29
Da tun es auch schon die Standard-SQL-Queries, da es ja nur ein Befehl ist. Einfach den kompletten Create-Befehl per ExecSQL ausführen.
BTW: Warum noch 1.0? Gibt doch schon 1.5.1.
Cu,
Udontknow
|
|
UGrohne
      

Beiträge: 5502
Erhaltene Danke: 220
Windows 8 , Server 2012
D7 Pro, VS.NET 2012 (C#)
|
Verfasst: Fr 24.09.04 07:32
Nein, das geht nicht, da Du bei Queries und der IBSQL-Komponente nicht den Terminate ändern kannst. Zwar funktioniert damit folgendes Konstrukt:
Quelltext 1: 2: 3: 4: 5:
| CREATE PROCEDURE NEW_PROCEDURE AS begin suspend; end |
aber dieses schon nicht mehr:
Quelltext 1: 2: 3: 4: 5: 6: 7:
| CREATE PROCEDURE NEW_PROCEDURE AS DECLARE VARIABLE "COUNTER" INTEGER; begin SELECT count(*) FROM auftraege INTO :counter; suspend; end |
Du brauchst damit eine Script-Komponente, z.B. IBScript (ab IBX Version 7.08 dabei glaube ich, Update gibts auf bdn.borland.com). Da kannst Du das Terminator-Zeichen ändern, um solche verschachtelten Befehle auch ausführen zu können. Stellst Du den Terminator z.B. auf ^ ein, dann wird folgender Code (obiges Beispiel) korrekt ausgeführt:
Quelltext 1: 2: 3: 4: 5: 6: 7:
| CREATE PROCEDURE NEW_PROCEDURE AS DECLARE VARIABLE "COUNTER" INTEGER; begin SELECT count(*) FROM auftraege INTO :counter; suspend; end^ |
Hinter die vollständigen Anweisungen muss also der Terminator.
P.S.: Das hier ist getestet 
|
|
Udontknow
      
Beiträge: 2596
Win7
D2006 WIN32, .NET (C#)
|
Verfasst: Fr 24.09.04 07:41
Ich muss dir widersprechen. Der Terminator selber ist nur ein Hilfsmittel für das Skript-Tool, damit dies erkennt, wo der Befehl aufhört, und wo der nächste beginnt. Der SQL-Server interessiert sich dafür nicht.
Ich habe bei mir in der Firma ein Tool geschrieben, daß solche Skripts über eine DBX-SQL-Query in mehrere DBs nacheinander pumpt. Da gehe ich genau so vor: Alles bis zum Terminator-Zeichen einlesen, ExecSQL aufrufen, nächsten Befehl.
Da aber hier nur ein Create-Befehl vorliegt, muss man sich darum nicht kümmern.
Cu,
Udontknow
|
|
UGrohne
      

Beiträge: 5502
Erhaltene Danke: 220
Windows 8 , Server 2012
D7 Pro, VS.NET 2012 (C#)
|
Verfasst: Fr 24.09.04 07:48
Udontknow hat folgendes geschrieben: | Ich habe bei mir in der Firma ein Tool geschrieben, daß solche Skripts über eine DBX-SQL-Query in mehrere DBs nacheinander pumpt. Da gehe ich genau so vor: Alles bis zum Terminator-Zeichen einlesen, ExecSQL aufrufen, nächsten Befehl. |
Der ; ist aber der Terminator und der ist innerhalb der Stored Procedure auch schon. D.h. ja, dass Du dann nur die halbe Procedure einliest, das ausführst und dann den Rest. Das ist das einzige, was gehen könnte (da bin ich mir nicht sicher), aber das komplette Skript oben ausführen funktioniert bei mir auf jeden Fall mal nicht ...
|
|
Udontknow
      
Beiträge: 2596
Win7
D2006 WIN32, .NET (C#)
|
Verfasst: Fr 24.09.04 08:15
Delphi-Quelltext 1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14:
| var Str:String; begin Str:='Create procedure Test1'+#$D#$A+ 'returns'+#$D#$A+ '('+#$D#$A+ ' counter integer'+#$D#$A+ ')'+#$D#$A+ 'as'+#$D#$A+ 'begin'+#$D#$A+ ' select Count(*) from TABELLE into :counter;'+#$D#$A+ ' suspend;'+#$D#$A+ 'end;'; SQLConnection1.Execute(Str,NIL); end; |
Das klappt einwandfrei, obwohl da mehr als ein Semikolon auftaucht. Das liegt eben, wie bereits gesagt, daran, daß das Terminatorsymbol nur für das Parsen der Befehle wichtig ist, und das findet immer clientseitig statt! Der Server weiss nichts von einem Terminatorsymbol.
Cu,
Udontknow
|
|
UGrohne
      

Beiträge: 5502
Erhaltene Danke: 220
Windows 8 , Server 2012
D7 Pro, VS.NET 2012 (C#)
|
Verfasst: Fr 24.09.04 08:24
Sorry, aber hier verwendest Du doch gar kein Query oder eine SQL-Komponente. Du schickst das (anscheinend) direkt an den Server und somit ist das ja wohl was ganz anderes. Wir reden hier ja gerade über Queries. Außerdem bin ich auf die IBX-Komponenten eingegangen, evtl. hat dbExpress wieder ganz andere Eigenarten in der Hinsicht, das weiß ich nicht.
Somit hast Du meiner Aussage gar nicht widersprochen, sondern nur einen anderen Weg (über andere Komponenten) aufgezeigt, mit dem es auch geht.
|
|
Udontknow
      
Beiträge: 2596
Win7
D2006 WIN32, .NET (C#)
|
Verfasst: Fr 24.09.04 08:38
Ist die SQLConnection etwa keine SQL-Komponente?
Also, irgendwie ging es doch darum, ob man nun eine Script-Komponente für einen Create-Procedure-Befehl braucht oder nicht, und die Antwort lautet "Nein, braucht man nicht, egal, wie komplex die Prozedur auch ist".
*GRÜBEL*
Ehrlich gesagt, ich glaube, ich habe das noch nie mit eine Query probiert, das muss ich mal austesten.
Cu,
Udontknow
|
|
UGrohne
      

Beiträge: 5502
Erhaltene Danke: 220
Windows 8 , Server 2012
D7 Pro, VS.NET 2012 (C#)
|
Verfasst: Fr 24.09.04 08:43
Udontknow hat folgendes geschrieben: | Ehrlich gesagt, ich glaube, ich habe das noch nie mit eine Query probiert, das muss ich mal austesten. |
Hast Du das nicht in Deinem ersten Posting gesagt? Oder hab ich das falsch verstanden?
Außerdem wollte ich damit auch der Aussage von CenBells widersprechen, der ja IBSQL als Möglichkeit geäußert hatte und das geht definitiv nicht...
Ich glaube, wir haben voll aneinander vorbei geredet 
|
|
Udontknow
      
Beiträge: 2596
Win7
D2006 WIN32, .NET (C#)
|
Verfasst: Fr 24.09.04 08:49
Hmmm, stimmt schon, im ersten Post habe ich von einer Query geschrieben, das geht aber nicht, und ich weiss jetzt auch wieder, warum das so ist!
TDataset-Nachfahren können so ein Statement nicht ausführen, da sie bspw. ":counter" für einen Dataset-Parameter halten und diesen ersetzen. Deshalb bin ich dann auch auf die Connection-Kompo ausgewichen. Kannst du bitte mal schauen, ob es eine Methode Execute auch bei den IBX-Kompos gibt? Unter BDE gibt es diesen Befehl auch.
Cu,
Udontknow
|
|
UGrohne
      

Beiträge: 5502
Erhaltene Danke: 220
Windows 8 , Server 2012
D7 Pro, VS.NET 2012 (C#)
|
Verfasst: Fr 24.09.04 08:59
Verdammt, der : ist mir nicht eingefallen. OK, ohne : würde das auch mit IBSQL funktionieren  . Aber auch der : schließt die Erzeugung von SPs mit IBSQL aus, weil in min. 70% der Fälle irgendwo einer auftaucht
IBDatabase hat leider keine solche Execute-Methode, damit fällt das dann leider schon mal flach ...
|
|
Udontknow
      
Beiträge: 2596
Win7
D2006 WIN32, .NET (C#)
|
Verfasst: Fr 24.09.04 09:07
Na, da habe ich wohl mit DBX intuitiv die richtigen Komponenten genommen.
Gibts bei IBX vielleicht irgendeine weitere Komponente, die für so etwas verwendet wird?
Cu,
Udontknow
|
|
UGrohne
      

Beiträge: 5502
Erhaltene Danke: 220
Windows 8 , Server 2012
D7 Pro, VS.NET 2012 (C#)
|
Verfasst: Fr 24.09.04 09:12
Udontknow hat folgendes geschrieben: | Na, da habe ich wohl mit DBX intuitiv die richtigen Komponenten genommen.
Gibts bei IBX vielleicht irgendeine weitere Komponente, die für so etwas verwendet wird?
|
Naja, über die "richtigen" wollen wir jetzt mal nicht streiten
Es gibt bei IBX seit 7.08 wie gesagt die IBScript-Komponente, mit der komplette SQL-Scripts ausgeführt werden können ...
|
|
OlliWausD 
      
Beiträge: 212
Win 2000/XP
Delphi 5 Professional - Interbase/Firebird
|
Verfasst: Fr 24.09.04 09:54
wow, hier hat sich ja einiges getan
ich muss allerdings noch einmal nachhaken
Also: Es ist nicht möglich in einer Query eine Stored Procedure zu erstellen, wegen dem ":", richtig?
Es gibt eine Möglichkeit über:
Udontknow hat geschrieben:
Delphi-Quelltext 1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14:
| var Str:String; begin Str:='Create procedure Test1'+#$D#$A+ 'returns'+#$D#$A+ '('+#$D#$A+ ' counter integer'+#$D#$A+ ')'+#$D#$A+ 'as'+#$D#$A+ 'begin'+#$D#$A+ ' select Count(*) from TABELLE into :counter;'+#$D#$A+ ' suspend;'+#$D#$A+ 'end;'; SQLConnection1.Execute(Str,NIL); end; |
wobei ich mit dem Code leider nichts anfangen kann. --> Detail-Beschreibung wäre super, wenn du das für mich machen würdest. Das +#$D#$A sagt mir nämlich überhaupt nix
UGrohnehat geschrieben
Zitat: |
Du brauchst damit eine Script-Komponente, z.B. IBScript (ab IBX Version 7.08 dabei glaube ich, Update gibts auf bdn.borland.com). Da kannst Du das Terminator-Zeichen ändern, um solche verschachtelten Befehle auch ausführen zu können. Stellst Du den Terminator z.B. auf ^ ein, dann wird folgender Code (obiges Beispiel) korrekt ausgeführt:
Delphi-Quelltext 1: 2: 3: 4: 5: 6: 7:
| CREATE PROCEDURE NEW_PROCEDURE AS DECLARE VARIABLE "COUNTER" INTEGER; begin SELECT count |
Hinter die vollständigen Anweisungen muss also der Terminator.
P.S.: Das hier ist getestet
|
Wie funktioniert dass dann genauer?? Schreib ich in die Komponente einfach den Createbefehl bei ausführung hab ich dann eine SP in der DB??
Das bringt mich zur nächsten Frage:
Kann ich eine "Virtuelle SP" zu Laufzeit erstellen, die nur dort erstellt wird, wo ich sie brauche?? --> Meine DB Quillt nämlich schon fast über vor SPs
Quasi so:
Funktioniert es eine Query1 zu erstellen:
Delphi-Quelltext 1:
| select * from Umsatz where Kunden.nr = 12345 |
Und auf diese Query, quasi auf das Ergebnis eine weitere Abfrage zu setzen, quasi so ähnlich wie auf eine Stored Procedure???
Delphi-Quelltext 1:
| select * from Query1Ausgabedaten where Datum = '23.09.2004 09:45' |
Gut: ist jetzt ein blödes Beispiel, aber ich denke, ihr wisst was gemeint ist.
Von der Logic her müsste es funktionieren, aber funktioniert das mit Delphi, bzw. Firebird??
Olliw
ps.:
Udontknow hat geschrieben:
Zitat: | BTW: Warum noch 1.0? Gibt doch schon 1.5.1. |
ganz einfach:
Die Kunden haben alle 1.0 --> gleiches Testsystem wie hier.
V1.5 is noch nicht getestet, und außerdem müßte ich wieder verschiedene Sachen anpacken, weil die Sicherheitsdatenbank nicht mehr isc4 sondern secure heisst !
_________________ Take it easy
|
|
Udontknow
      
Beiträge: 2596
Win7
D2006 WIN32, .NET (C#)
|
Verfasst: Fr 24.09.04 09:57
Zitat: | wobei ich mit dem Code leider nichts anfangen kann. --> Detail-Beschreibung wäre super, wenn du das für mich machen würdest. Das +#$D#$A sagt mir nämlich überhaupt nix |
Das ist nur Code für den Zeilenumbruch. Also enthält der String einfach nur
Quelltext 1: 2: 3: 4: 5: 6: 7:
| CREATE PROCEDURE NEW_PROCEDURE AS DECLARE VARIABLE COUNTER INTEGER; begin SELECT count(*) FROM auftraege INTO :counter; suspend; end |
ICh führe den Befehl in der Variable STR anschliessend über Die TSQLConnection (Datenbank)-Komponente aus. Wenn du auch DBExpress nutzt oder die BDE, kannst du genauso verfahren, mit IBX scheints nicht so einfach zu sein.
Edit: Hey, das ist mein 2000. Beitrag!
Cu,
Udontknow
|
|
UGrohne
      

Beiträge: 5502
Erhaltene Danke: 220
Windows 8 , Server 2012
D7 Pro, VS.NET 2012 (C#)
|
Verfasst: Fr 24.09.04 10:10
OlliWausD hat folgendes geschrieben: |
Das bringt mich zur nächsten Frage:
Kann ich eine "Virtuelle SP" zu Laufzeit erstellen, die nur dort erstellt wird, wo ich sie brauche?? --> Meine DB Quillt nämlich schon fast über vor SPs
Quasi so:
Funktioniert es eine Query1 zu erstellen:
Delphi-Quelltext 1:
| select * from Umsatz where Kunden.nr = 12345 |
Und auf diese Query, quasi auf das Ergebnis eine weitere Abfrage zu setzen, quasi so ähnlich wie auf eine Stored Procedure???
Delphi-Quelltext 1:
| select * from Query1Ausgabedaten where Datum = '23.09.2004 09:45' |
Gut: ist jetzt ein blödes Beispiel, aber ich denke, ihr wisst was gemeint ist.
Von der Logic her müsste es funktionieren, aber funktioniert das mit Delphi, bzw. Firebird??
|
Eine virtuelle SP halte ich für sinnlos, zumal es relativ aufwändig ist, eine SP zu erstellen, auszuführen und danach wieder zu löschen (aufwändig im Sinne von langsam). Außerdem weiß ich nicht, ob da noch irgendwelche anderen Nachteile entstehen...
Solltest Du nach mehreren Sacehn filtern wollen, verwende einfach mehrere Bedingungen:
Quelltext 1:
| SELECT * FROM umsatz where Kunden.nr=12345 and Datum='23.09.2004 09:45' |
Solltest Du das Query nachträglich filtern müssen, kannst Du auch mit Filter (vom Query) oder Locate arbeiten.
Außerdem solltest Du auch überlegen, ob Du irgendwo statt SPs ein paar Views einsetzen kannst.
|
|
CenBells
      
Beiträge: 1547
Win 7
Delphi XE5 Pro
|
Verfasst: Fr 24.09.04 10:54
UGrohne hat folgendes geschrieben: | Hast Du das nicht in Deinem ersten Posting gesagt? Oder hab ich das falsch verstanden?
Außerdem wollte ich damit auch der Aussage von CenBells widersprechen, der ja IBSQL als Möglichkeit geäußert hatte und das geht definitiv nicht...
Ich glaube, wir haben voll aneinander vorbei geredet  |
Hi,
na, hier ist ja ne heiße diskussion entbrannt
Also ich meinte Natürlich auch IBScript.
Das sollte für OlliWAusD auch kein problem sein. Einfach mal das neueste IBX Update herunterziehen und installieren. Dann kann er wie vorher weiterarbeiten - mit dem unterschied, daß er jetzt auch IBScript verwenden kann.
Aber nochmal kurz zurück zu der geschichte mit dem : und dem Terminator, *delphi start* Ich habe mir vor etwa einem Jahr mal eine Kompo geschrieben, die mir DB-Updates ausführt und damals habe ich soweit ich weiß anfangs noch nicht IBScript für die Stored Procedures verwendet..... Der Variablenname in meiner Proc sagt, daß es wohl früher mal ein IBSQL war, aber das habe ich geändert. Wahrscheinlich gingen die DDL-Statements wirklich nicht
[edit]Habe jetzt mal den Quellcode von IBSQL durchgesehen. Da gibt es zumindest die Option, daß man DDL statements absetzen kann. vielleicht geht es doch?!?[/edit]
Naja, eigentlich ist das ja nun auch egal
Also, gerade nochmal nachgeschaut.
Ich habe nirgendwo den Terminator der IBScript Kompo verändert. Das heißt, ich schreibe ganz normal meine Stored Procedure und weise den String dann der IBScript Kompo zu und führe das dann aus
Beispiel
Delphi-Quelltext 1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18:
| var LStatement: String; begin ... LStatement := 'Create Procedure Test'#13#10 + 'AS'#13#10 + 'Begin '#13#10 + ' --tue was'#13#10 + ' suspend;'#13#10 + 'End'; IBScript.Script.Add(LStatement); try IBScript.ExecuteScript; except end; end; |
Also, @OlliWAusD IBX 7.08 nehmen und glücklich sein
Gruß
KEn
_________________ Eine Klasse beschreibt die Struktur und das Verhalten einer Menge gleichartiger Objekte.
|
|
OlliWausD 
      
Beiträge: 212
Win 2000/XP
Delphi 5 Professional - Interbase/Firebird
|
Verfasst: Fr 24.09.04 12:36
UGrohne hat folgendes geschrieben: |
Eine virtuelle SP halte ich für sinnlos, zumal es relativ aufwändig ist, eine SP zu erstellen, auszuführen und danach wieder zu löschen (aufwändig im Sinne von langsam). Außerdem weiß ich nicht, ob da noch irgendwelche anderen Nachteile entstehen...
Solltest Du nach mehreren Sacehn filtern wollen, verwende einfach mehrere Bedingungen:
Quelltext 1:
| SELECT * FROM umsatz where Kunden.nr=12345 and Datum='23.09.2004 09:45' |
Solltest Du das Query nachträglich filtern müssen, kannst Du auch mit Filter (vom Query) oder Locate arbeiten.
Außerdem solltest Du auch überlegen, ob Du irgendwo statt SPs ein paar Views einsetzen kannst. |
das ist mir schon klar, das ich mit WHERE mehrere Sachen Filtern kann, UGrohne
mir geht es aber darum:
Ich bin gerade dabei eine Vertreterprovisionsabrechnung zu schreiben. Jeder der sich schon mal mit dem Thema befasst hat, weiss, dass es bei großen Datenbanken enorm schwirig ist, diese in einer vernünftigen Zeit zu errechnen. Und was dazukommt ist, dass diese ja noch gut Designt, und übersichtlich sein soll.
ich hab es mittlerweile so programmiert, dass ich bei einer DB mit 500000 Rechnungspositionen innerhalb von ca 5sec hinkommt. Dafür hab ich, um die Datenmenge gering zu halten
2 Stored Proceduren und
1 Query übereinandergelegt
SP1: Auslesen aller Rechnungen und bei einer Gutschrift den Wert der Summe auf "-" setzen, bezogen auf den Vertreter
SP2: Die Datenmenge aus SP1 (wesentlich kleiner, da nur die DS des Vertreters) mit extjahr, ... verifiziert und in der
Query, welche auf der Datenmenge von SP2 verweist, gruppiert, und entsprechen im Gui platziert.
Das Problem ist jedoch, dass ich diese SP ja wirklich nur hier brauche, und sie in der DB eigentlich nichts zu suchen haben, wenn ich sie nur so selten verwende. Mittlerweile sinds über 50 SP in der DB, und das nerft mich.
Deswegen die Frage, ob ich diese zur Laufzeit erstellen kann (virtuell), um die SP's in der DB gering zu halten.
mfg
Olli W
_________________ Take it easy
|
|
|