![]() |
Datenbank: FB • Version: 2 • Zugriff über: egal
FB: Prepared Query mit In-Statement ?
Hallo,
ich habe eine Query, die wird 100mal ausgeführt. Select Feld3 From Tab Where (Feld1=:Feld1) And (Feld2 In :Feld2) Feld1 ist Integer Feld2 ein String oder String-Liste Leider kann ich die Query nicht preparen wegen dem In. Geht das irgendwie anders ?? |
AW: FB: Prepared Query mit In-Statement ?
Was steht den in dem Parameter Feld2?
|
AW: FB: Prepared Query mit In-Statement ?
Warum geht das nicht?
Fehlermeldung? Quelltext mit Parameterbefüllung und konkreten Beispieldaten? |
AW: FB: Prepared Query mit In-Statement ?
IN unterstützt keine Parameter.
|
AW: FB: Prepared Query mit In-Statement ?
Jain, so absolut stimmt das nicht.
Je Parameter darf nur ein Wert übergeben werden. Dashier funktioniert:
Delphi-Quellcode:
Dashier funktioniert ebenfalls:
qry.Close;
qry.SQL.Clear; qry.SQL.Add('select feld3 from tabelle where feld1 = :feld1 '); qry.SQL.Add('and feld2 in (:feld2) '); qry.Prepare; qry.Params[0].AsInteger := 1; qry.Params[1].AsString := '''Feldinhalt'''; qry.Open; ShowMessage(Format('%d',[qry.RecordCount])); qry.Close;
Delphi-Quellcode:
Dashier funktioniert jedoch nicht:
qry.Close;
qry.SQL.Clear; qry.SQL.Add('select feld3 from tabelle where feld1 = :feld1 '); qry.SQL.Add('and feld2 in (:feld2a,:feld2b,:feld2c) '); qry.Prepare; qry.Params[0].AsInteger := 1; qry.Params[1].AsString := '''FeldinhaltA'''; qry.Params[2].AsString := '''FeldinhaltB'''; qry.Params[3].AsString := '''FeldinhaltC'''; qry.Open; ShowMessage(Format('%d',[qry.RecordCount])); qry.Close;
Delphi-Quellcode:
qry.Close;
qry.SQL.Clear; qry.SQL.Add('select feld3 from tabelle where feld1 = :feld1 '); qry.SQL.Add('and feld2 in (:feld2) '); qry.Prepare; qry.Params[0].AsInteger := 1; qry.Params[1].AsString := '''FeldinhaltA'',''FeldinhaltB'',''FeldinhaltC'''; qry.Open; ShowMessage(Format('%d',[qry.RecordCount])); qry.Close; |
AW: FB: Prepared Query mit In-Statement ?
Hallo,
Fehlermeldung beim Prepare "Token ? unknown" Feld2 ist eine variable Anzahl von Strings. Ich habe hier IBExpert und IBDAC. Das das Prepare nicht geht, ist ja bekannt, wie könnte man das denn lösen? Ich möchte ungern X prepared Queries (pro Anzahl der Strings eine) bauen, sehe das aber als einzige Lösung. |
AW: FB: Prepared Query mit In-Statement ?
Token unknown lässt auf einen Syntaxfehler im SQL schließen, vermutlich ist das aber nur eine Teilmenge der Fehlermeldung.
Bitte mal das vollständige SQL und die vollständige Fehlermeldung. So ist das nur was für die :glaskugel: Ein Parameter = ein Wert. Wenn ein Wert aus mehreren Zeichenfolgen besteht, geht das. Wenn ein Parameter aber mehrere einzelne Werte enthält, die eigentlich separat ins IN sollen, dann geht das nicht.
Delphi-Quellcode:
funktioniert.
qry.SQL.Text := 'select * from x where feld2 IN (:Parameter)';
qry.Params[0].AsString := 'Das ist jetzt mal etwas Text.'; Das wird zu
SQL-Code:
, wobei hier das IN auch durch ein = ersetzt werden könnte.
select * from x where feld2 IN ('Das ist jetzt mal etwas Text.')
Delphi-Quellcode:
funktioniert, kann aber zu einem deutlich anderen Ergebnis, als die vorherige Variante, führen.
qry.SQL.Text := 'select * from x where feld2 IN (:P1,:P2,:P3,:P4,:P5,:P6)';
qry.Params[0].AsString := 'Das' qry.Params[1].AsString := 'ist' qry.Params[2].AsString := 'jetzt' qry.Params[3].AsString := 'mal' qry.Params[4].AsString := 'etwas' qry.Params[5].AsString := 'Text.'
Delphi-Quellcode:
funktioniert eventuell technisch. Im IN steht aber nur ein Wert, nach dem gesucht werden soll, und nicht sechs Werte, wie der Aufbau des Parameters suggerieren könnte. Und wenn hier die Anzahl der ' nicht so ganz passt, könnte die daraus resultierende Fehlermeldung auch 'Token unknown' enthalten.
qry.SQL.Text := 'select * from x where feld2 IN (:Parameter)';
qry.Params[0].AsString := '''Das'',''ist'',''jetzt'',''mal'',''etwas'',''Text.'''; |
AW: FB: Prepared Query mit In-Statement ?
Das IN ist ja faktisch nur eine Kurzform für mehrere OR-verknüpfte Werte. Und mehrere Werte bekommt man eben nicht dynamisch parametrisiert. Klingt blöd, is aber so.
|
AW: FB: Prepared Query mit In-Statement ?
Hallo,
der Fehler kommt bereits beim Prepare, hat also nichts mit der Anzahl der Strings im Parameter zu tun. FB macht das schon richtig so, dass es sagt, IN kann nicht prepared werden. Token unknown lässt auf einen Syntaxfehler im SQL schließen, vermutlich ist das aber nur eine Teilmenge der Fehlermeldung. Nein, ohne das IN funktioniert es. |
AW: FB: Prepared Query mit In-Statement ?
Zitat:
SQL-Code:
Die Klammern dürfen nicht Teil des Parameterinhaltes sein. Ist dem so, so ist "Token unknown" ein Teil der Fehlermeldung.
Select Feld3 From Tab
Where (Feld1=:Feld1) And (Feld2 In (:Feld2)) Vollständig dürfte sie in etwa Zitat:
Zitat:
Um Die Syntax für das Prepare zu prüfen, gehe ich zum Testen immer her und mache um die Parameter Hochkommata. Also
SQL-Code:
bei Deinem Statement. Das wird auch scheitern, da es ein ungültiges SQL ist. Die Klammern beim IN fehlen!!!
Select Feld3 From Tab
Where (Feld1=':Feld1') And (Feld2 In ':Feld2') Parameter können nur Werte enthalten, aber nicht Teile des SQLs. Die Klammern sind aber Teile des SQLs.
SQL-Code:
Select Feld3 From Tab
Where (Feld1=:Feld1) And (Feld2 :Feld2)
Delphi-Quellcode:
geht ja auch nicht oder gar
qry.params[0] := 'in (1,2,3)';
SQL-Code:
Select Feld3 From Tab
Where (Feld1=:Feld1) And (:Feld2)
Delphi-Quellcode:
geht auch nicht.
qry.params[0] := 'feld2 in (1,2,3)';
|
AW: FB: Prepared Query mit In-Statement ?
"100 mal eine Query"
Klingt etwas nach der berühmten Whileschleife für Queries. Häufig kann man das IN zu einem JOIN auflösen. Das hilft nicht unbedingt weiter, außer in einem speziellen Fall. Wenn nämliche die vielen IN Werte alle an einem oder wenigen "Parent" Werten einer übergeordneten Tabelle hängen. Gegenanzeige wäre bspw. das in dem IN disjunkte Werte aus einer Suchmaske stecken. Wenn also die Zahl 100 darauf hindeutet, das in dieser 100er Schleife eine Dimension oder Menge durchgearbeitet wird, die man auch insgesamt in eine "große" Query auflösen kann, wäre das eine mögliche Lösung, das IN fliegt dann idealer Weise raus. Also Frage wäre: Gibt es zu den 100 Abfragen eine Master Query? Und wenn ja, wie sieht die aus? Handarbeitslösung: Die IN Werte in eine (temporäre) User spezifische Tabelle eintragen und die jetzige Query dagegen joinen. Oder bei einer bekannten Maximalanzahl von IN Werten, z.B. 5, mit 5 verschiedenen Queries arbeiten und jeweils die Query starten, die dazu dieser Parameter Anzahl entspricht. Oder den fixen Teil der Query in einen View packen und auf Parametrieung und Prepare der IN Anweisung verzichten (dann ist wenigsten der View fertig prepared). |
AW: FB: Prepared Query mit In-Statement ?
Zitat:
1. bei kleineren Datenmengen so
Code:
dabei musst du dann einfach deinen Parameter P2 als semikolon getrennte Liste mit führendem und abschliessendem
Select Feld3 From Tab
Where (Feld1=:P1) And (:P2 containing ';'||Feld2||';' ) Semikolon als String übergeben, z.B. so
Code:
Das sollte klappen, ist aber von der Performance nur für kleine Datenmenge sinnvoll, weil es garantiert einen
qry.Params[0].AsInteger := 123;
qry.Params[1].AsString := ';a;b;x;'; Full Table Scan macht 2. Je nach Netzwerkspeed und Anzahl an Parametern sollte man die Vorteile von prepare nicht überschätzen und einfach den kompletten SQL so wie du den brauchst mit konstanten im SQL Text übertragen , d.h.
Code:
3. Die optimalere Lösungs ggf auch für große Datenmenge
Select Feld3 From Tab
Where (Feld1=123) And (Feld2 in ('a','b','x') ) Erstelle eine Global Temporary Table mit on commit delete rows wo nur mögliche Parameter reinkommen, Index anlegen ggf nicht vergessen und packe deine Parameter in die Tabelle
Code:
In der Global Temporary Table GTT siehst du immer nur die Daten deiner eigenen Connection.
CREATE GLOBAL TEMPORARY TABLE BRPARRAY (
VAL VARCHAR(80) NOT NULL PRIMARY KEY ) ON COMMIT DELETE ROWS; commit; INSERT INTO BRPARRAY VALUES ('a'); INSERT INTO BRPARRAY VALUES ('b'); INSERT INTO BRPARRAY VALUES ('x'); --achtung hier kein commit, sonst ist wegen on commit delete rows die tabelle wieder leer Select Feld3 From Tab join brparray on brparray.val=tab.feld2 Where (Feld1=123) Mit on commit delete rows ist die nach dem commit leer Mit on commit preserve rows ist die auch nach dem commit noch gefüllt, dann ggf einfach selber entscheiden wann gelöscht werden soll. Wir nutzen GTT zB dafür, das beim Programmstart die Userrechte und Translations einmalig ausgelesen werden und immer in den GTTs drin sind, man also bei jeder Abfrage zB PLZ Werte entsprechend der eigenen Rechte da drin zu haben und jede Abfrage kann immer an eine oder mehrere passende GTTs gejoint werden. |
AW: FB: Prepared Query mit In-Statement ?
Hallo,
die 100 habe ich mal so hingeschrieben. Es können auch mehr sein. Die betreffende Query hat noch keinen Outer Join, der macht das Umbauen in eine einzige Query noch viel langsamer. Das Containing klingt doch schon mal gut. Aber das kann doch nicht stimmen, ich habe z.B. 12 und 12B in der Datenbank, suche ich jetzt über Containg ;12;, wird auch das 12B gefunden, richtig? Das könnte ich aber über eine nachträgliches If beim Durchlaufen der Query lösen. Ein Full Table Scan ist es nicht, weil Field1 indiziert ist. PS: Der Code ist alt. Ich versuche ihn zu Optimieren, ohne alles neu schreiben zu müssen. |
AW: FB: Prepared Query mit In-Statement ?
Zitat:
Gruß K-H |
AW: FB: Prepared Query mit In-Statement ?
Hallo,
das Problem ist nicht die Abfrage, sondern der dahinterliegende Code. Da habe ich einfach keine Lust, den zu ändern. Der Mehrfachaufruf kommt halt von der prozeduralen Rangehensweise: - ermittle Anzahl der Gruppenmitglieder - ermittle pro Gruppenmitglied diverse Daten (for-Schleife) je nach Art des Mitgliedes sind es andere Daten |
AW: FB: Prepared Query mit In-Statement ?
Verzichte auf das Prepare und baue das SQL jeweils zusammen.
Die Verwendung von IN im Zusammenhang mit Parametern ist eher grenzwertig, insbesondere dann, wenn die Menge der Werte innerhalb des IN von Statement zu Statement variiert. |
AW: FB: Prepared Query mit In-Statement ?
Hallo,
genauso läuft es ja jetzt. Ich habe etwa 500 variierende Mitglieder in einer Personengruppe. Jedes Mitglied hat 1 bis x Aktivitäten, die angezeigt werden sollen. Von den 500 Mitgliedern sind immer so 100-200 aktiv. |
AW: FB: Prepared Query mit In-Statement ?
Zitat:
Die DB würde sich freuen, vielleicht sogar der Codeleser und Versteher. SQL ist genau dafür geschaffen, Daten zu verknüpfen und zu transformieren. Für eine prozedurale Lösung- zur Datenzusammenstellung wohlgemerkt- gibt es nur selten Argumente. Eine Fall basierte Business Logik, die anhand der Daten dann unterschiedliche Aktivitäten(! nicht Selektionen) startet, ist im Client gut aufgehoben. (Geht auch anders, ist aber hier nicht das Thema) Guten Rutsch! |
AW: FB: Prepared Query mit In-Statement ?
Zitat:
im parameter gesucht wird, ja immer ein Semikolon davor und dahinter dynamisch ergänzt ist ';12B;13;13A;' containing ';12;' ist false du musst deinen parameter sauber mit Trenner zusammenbauen |
AW: FB: Prepared Query mit In-Statement ?
Hallo,
Jobs ja, will ich aber nicht :) Holger dann verstehe ich das Containing nicht Ah, auch das Select anpassen! |
AW: FB: Prepared Query mit In-Statement ?
Hallo,
so, ich hatte jetzt mal Zeit, das Prepare nach Holgers Anleitung einzubauen. Ergebnis: nur minimale Verbesserung der Performance Die Anzahl der Queries ist hier halt doch entscheidend. |
Alle Zeitangaben in WEZ +1. Es ist jetzt 08:15 Uhr. |
Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz