Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Datenbanken (https://www.delphipraxis.net/15-datenbanken/)
-   -   Delphi Tabelle/Query, die ihre Daten aus einer anderen Query bezieht (https://www.delphipraxis.net/164799-tabelle-query-die-ihre-daten-aus-einer-anderen-query-bezieht.html)

RSE 30. Nov 2011 10:44

Datenbank: InterBase • Version: 6.1 • Zugriff über: IBObjects

Tabelle/Query, die ihre Daten aus einer anderen Query bezieht
 
Hallo Leute,

wir arbeiten mit Delphi 5 und den IBObjects (TIBOQuery usw.). Gibt es die Möglichkeit, eine Query, ein Table oder irgendein anderes TDataSet so zu benutzen, dass es sich die Daten nicht aus der Datenbank, sondern aus einer anderen Query holt? Das Anwendungsszenario sieht folgendermaßen aus: Ich habe eine Tabelle, in der gesucht werden kann. Die Daten werden währenddessen in einem Tabellen-Control angezeigt. Nun möchte ich, dass sich bei jedem Tastenanschlag in einem Suchfeld die Anzeige weiter einschränkt. Ich kann also nicht jedes Mal eine neue DB-Anfrage machen, nur um eine Teilmenge der schon geholten Daten nochmals zu holen. Stattdessen möchte ich einfach die schon bekannten Daten nutzen und davon nur eine Teilmenge darstellen. Es handelt sich um größere Datenmengen (mehrere 10.000 Datensätze).

Ich weiß, dass das TClientDataSet dazu wie geschaffen ist. Dessen Einsatz steht aber außer Frage, da wir noch in Delphi 5 programmieren und hier die Nutzung nur erfolgen kann, wenn die midas.dll auf allen Clients installiert und registriert ist (Uses LibMidas ist erst ab D6 möglich) und das können wir nicht sicherstellen.

jaevencooler 30. Nov 2011 12:05

AW: Tabelle/Query, die ihre Daten aus einer anderen Query bezieht
 
Moin, Moin,


Die Idee eine Query mit dem kompletten Datenbestand einmalig öffnen, und dann mit einer weiteren Query
darauf zu greifen wird nicht funktionieren !

Schon mal über die Verwendung eines Filters nachgedacht, oder eventuell mit Locate arbeiten ?

Die bessere Alternative für eine schnelle Suche innerhalb der Daten ist auf jeden Fall die
Daten gut und geschickt zu indizieren, und alle Möglichkeiten Deines Datenbankservers zu nutzen.

Was für eine RDBMS setzt Du denn ein ?
(Ups, wer lesen kann ....)


Beste Grüße
Michael

RSE 30. Nov 2011 12:38

AW: Tabelle/Query, die ihre Daten aus einer anderen Query bezieht
 
Wenn ich bei jedem Tastenanschlag eine DB-Abfrage starten würde, dann wäre das einfach nur elendig langsam. Allein die Latenz durch das LAN ist doch schon zu langsam dafür - egal wie schnell der Server reagieren würde. Deshalb möchte ich die Einschränkung lokal berechnen, und zwar vorzugsweise nur für so viele Datensätze wie ich grad brauche (wie angezeigt werden).

Tastenanschlag -> Grid unter Berücksichtigung der neuen Bedingungen mit so vielen Datensätzen füllen, wie angezeigt werden

Das Ganze muss also in Sekundenbruchteilen (Hundertstel) passieren!

Bummi 30. Nov 2011 12:53

AW: Tabelle/Query, die ihre Daten aus einer anderen Query bezieht
 
klingt so als ob Du Filter verwenden solltest ....

stahli 30. Nov 2011 13:00

AW: Tabelle/Query, die ihre Daten aus einer anderen Query bezieht
 
Ich denke, der Ansatz ist nicht optimal. Ein Tastenanschlag (bzw. Suchänderung) könnte ja auch bedeuten, dass aus dem Suchstring etwas gelöscht wurde. Dann kommst Du mit einer weiteren Subfilterung nicht mehr zurecht.
Du solltest versuchen, immer komplett neu zu selectieren/zu filtern und diesen Vorgang bestmöglich zu optimieren. Das wäre jedenfalls mein Ansatz.

Ich habe ein altes Projekt, bei dem ich anhand von Sucheingaben einen Datensatz lokalisiere. Das erfolgt bei jeder Suchtextänderung indem erst in einer Straßen-Tabelle nach einem passenden Straßenindex gesucht wird und dann in einer Grundstücks-Tabelle nach dem Straßenindex und der passenden Hausnummer. Durch die Trennung in zwei Tabellen und Index-Verwendung geht das sehr schnell.

Vielleicht kannst Du ja Deine DB noch optimieren?

dataspider 30. Nov 2011 13:03

AW: Tabelle/Query, die ihre Daten aus einer anderen Query bezieht
 
Zitat:

Zitat von Bummi (Beitrag 1138591)
klingt so als ob Du Filter verwenden solltest ....

IBO setzt Filter in ein Where um und schickt die Abfrage zuzm Server.
Dieses lokale Filtern geht wohl z.B. in FibPlus.

Zitat:

Zitat von RSE (Beitrag 1138589)
Tastenanschlag -> Grid unter Berücksichtigung der neuen Bedingungen mit so vielen Datensätzen füllen, wie angezeigt werden

Das Ganze muss also in Sekundenbruchteilen (Hundertstel) passieren!

Wenn du das schaffst, geb ich einen aus.
Ich weiß ja nicht, was du als "Tabellencontrol" benutzt.
Aber allein das Neu Laden der gefilterten Daten in der Grid dauert lange genug.

Aus gutem Grunde gibt es dieses Verhalten in diversen LookUp - Komponenten.
Aber ich würde nie auf die Idee kommen, eine Rechnung über ein LookUp zu suchen.
Für Anreden, Mengenneinheiten - eben kleinere Tabellen - ist das OK.

Aber wenn du es versuchen willst, dann benutze diverse MemDatasets.
Diese können meist per Assign Daten und Struktur eines TDataSet übernehmen.

Ich würde aber bei so vielen Daten immer Eingabe - Enter - Suchen bevorzugen.
Evtll. noch durch einen Timer, welcher nach ca. 1 Sekunde Pause automatisch filtert.

Frank

RSE 30. Nov 2011 13:22

AW: Tabelle/Query, die ihre Daten aus einer anderen Query bezieht
 
Ich habe mich jetzt ein wenig zu TIBOQuery und Filtern belesen. In den IBO-FAQ steht folgendes:
Zitat:

The Locate() method for TIB_Query seems to work well. Is there a way to do a "LocateNext"?
You will find that this works rather nicely: instead of using the Locate() method, you can leave the Filtered property False and set a filter based on the value you are locating. Then, use the FindFirst, FindNext, FindLast, etc. methods to navigate through the records isolated by the locate (filter) criteria.
Ich denke ich werde dieses Verhalten benutzen. Ich fange dann bei jedem Tastenanschlag an zu filtern. Dabei werde ich Application.Processmessages einbauen und wenn zwischenzeitlich ein neuer Tastenanschlag aufgetreten ist, breche ich ab. Dann läuft die neu getriggerte Filterung an. So sollte das Ganze performant bleiben und trotzdem sofort Ergebnisse ausspucken.

EarlyBird 30. Nov 2011 14:17

AW: Tabelle/Query, die ihre Daten aus einer anderen Query bezieht
 
hat die Komponente eventuell ein onFilterRecord Ereignis?
In dem Ereignis kannst Du nach Deinen Kriterien Filtern.
Ich nutze es mit TMSQuery da funktioniert es super und blitz schnell

joachimd 30. Nov 2011 14:27

AW: Tabelle/Query, die ihre Daten aus einer anderen Query bezieht
 
Zitat:

Zitat von RSE (Beitrag 1138589)
Wenn ich bei jedem Tastenanschlag eine DB-Abfrage starten würde, dann wäre das einfach nur elendig langsam.

Ich mache dies i.d.R. so:
  1. Ein Tastenanschlag zieht einen timer auf, der zB auf 100 ms eingestellt ist
    Delphi-Quellcode:
    timer1.enabled:=false;
    timer1.interval:=100;
    timer1.enabled:=true;
  2. im Timer-Event wird der Timer Disabled und die Daten geladen
    Delphi-Quellcode:
    timer1.enabled:=false;
    //Lade Daten
  3. Falls Du noch eine Einschränkung brauchst, weil zB Deine Komponenten immer komplett laden wollen, setze ein TOP 30 in das Statement
    SQL-Code:
    SELECT TOP 30 * FROM mytable WHERE <Filter-Bedingung>

RSE 30. Nov 2011 14:47

AW: Tabelle/Query, die ihre Daten aus einer anderen Query bezieht
 
Zitat:

Zitat von joachimd (Beitrag 1138626)
Falls Du noch eine Einschränkung brauchst, weil zB Deine Komponenten immer komplett laden wollen, setze ein TOP 30 in das Statement
SQL-Code:
SELECT TOP 30 * FROM mytable WHERE <Filter-Bedingung>

Ich glaube nicht, dass InterBase 6.1 das kann ;-) Zumindest unserer nicht.

DeddyH 30. Nov 2011 14:50

AW: Tabelle/Query, die ihre Daten aus einer anderen Query bezieht
 
Und mit FIRST statt TOP?

RSE 30. Nov 2011 15:55

AW: Tabelle/Query, die ihre Daten aus einer anderen Query bezieht
 
Mit FIRST auch nicht, und LIMIT kann er auch nicht. Auszug aus der mir vorliegenden Hilfedatei:
Code:
SELECT [TRANSACTION transaction]
   [DISTINCT | ALL]
   {* | <val> [, <val> …]}
   [INTO :var [, :var …]]
   FROM <tableref> [, <tableref> …]
   [WHERE <search_condition>]
   [GROUP BY col [COLLATE collation] [, col [COLLATE collation] …]
   [HAVING <search_condition>]
   [UNION <select_expr> [ALL]]
   [PLAN <plan_expr>]
   [ORDER BY <order_list>]
   [FOR UPDATE [OF col [, col …]]];

<val> = {
   col [<array_dim>] | :variable
   | <constant> | <expr> | <function>
   | udf ([<val> [, <val> …]])
   | NULL | USER | RDB$DB_KEY | ? 
   } [COLLATE collation] [AS alias]
<array_dim> = [[x:]y [, [x:]y …]]
<constant> = num | 'string' | charsetname 'string'
<function> = COUNT (* | [ALL] <val> | DISTINCT <val>)
   | SUM ([ALL] <val> | DISTINCT <val>)
   | AVG ([ALL] <val> | DISTINCT <val>)
   | MAX ([ALL] <val> | DISTINCT <val>)
   | MIN ([ALL] <val> | DISTINCT <val>)
   | CAST (<val> AS <datatype>)
   | UPPER (<val>)
   | GEN_ID (generator, <val>)

<tableref> = <joined_table> | table | view | procedure
   [(<val> [, <val> …])] [alias]
<joined_table> = <tableref> <join_type> JOIN <tableref>
   ON <search_condition> | (<joined_table>)
<join_type> = [INNER] JOIN
   | {LEFT | RIGHT | FULL } [OUTER]} JOIN

<search_condition> = <val> <operator> {<val> | (
<select_one>)} 
   | <val> [NOT] BETWEEN <val> AND <val>
   | <val> [NOT] LIKE <val> [ESCAPE <val>]
   | <val> [NOT] IN (<val> [, <val> …] | <select_list>)
   | <val> IS [NOT] NULL
   | <val> {>= | <=} 
   | <val> [NOT] {= | < | >} 
   | {ALL | SOME | ANY} (<select_list>)
   | EXISTS (<select_expr>)

| SINGULAR (<select_expr>)
   | <val> [NOT] CONTAINING <val>
   | <val> [NOT] STARTING [WITH] <val>
   | (<search_condition>)
   | NOT <search_condition>
   | <search_condition> OR <search_condition>

| <search_condition> AND <search_condition>
<operator> = {= | < | > | <= | >= | !< | !> | <> | !=}
<plan_expr> =
   [JOIN | [SORT] [MERGE]] ({<plan_item> | <plan_expr>}
   [, {<plan_item> | <plan_expr>} …])

<plan_item> = {table | alias} 

{NATURAL | INDEX (<index> [, <index> …])| ORDER <index
>}
<order_list> =
   {col | int} [COLLATE collation]
      [ASC[ENDING] | DESC[ENDING]]
      [, <order_list> …]

RSE 30. Nov 2011 17:36

AW: Tabelle/Query, die ihre Daten aus einer anderen Query bezieht
 
Wenn ich einen Filter setze, gibt es eine Exception sobald ich FindFirst aufrufe (Filtered = False!). Er zerschießt das SQL irgendwo innerhalb von FindFirst, daher habe ich noch nicht einmal das zerschossene SQL als Text zur Analyse. Ich werde morgen noch den OnFilterRecord Event ausprobieren.

IBO Version 3.4.Ce auf Delphi 5

hoika 30. Nov 2011 21:17

AW: Tabelle/Query, die ihre Daten aus einer anderen Query bezieht
 
Hallo,

wenn es sich nur um die Daten einer Tabelle/Query handelt,
kannst du das TOP/LIMIT mit einer Stored Procedure nachbauen,
und ja, dass kann IB seit Version 4.2 ;)


Heiko

RSE 1. Dez 2011 10:49

AW: Tabelle/Query, die ihre Daten aus einer anderen Query bezieht
 
OnFilterRecord wird bei meiner Version von IBObjects (3.4.Ce) aufgrund eines Bugs nicht/nur manchmal aufgerufen. Da ich aber die Ergebnisse sowieso in ein Stringgrid einlese, kann ich ja auch beim Einlesen selbst aussortieren... Das Einfache liegt so nahe, dass man es übersieht!

Ich lese also ein, bis der nächste Tastenanschlag kommt, dann wird abgebrochen. Durch den neuen Tastenanschlag wird das Einlesen neu gestartet. Während des Einlesens habe ich ein Application.Processmessages eingebaut. Das ermöglicht mir Eingaben im Suchfeld (etwas hakelig, aber geht). DoClose und CloseQuery werden aber komischerweise erst ausgeführt, nachdem das Einlesen beendet ist, so dass ich es nicht abbrechen kann, wenn die Form geschlossen werden soll. Wieso wird das nicht beim nächsten Application.Processmessages aufgerufen?

RSE 1. Dez 2011 11:47

AW: Tabelle/Query, die ihre Daten aus einer anderen Query bezieht
 
Zitat:

Zitat von RSE (Beitrag 1138755)
Wieso wird das nicht beim nächsten Application.Processmessages aufgerufen?

Lösung: Mein Form ist modal, und bei modalen Fenstern wird lediglich ModalResult auf mrCancel gesetzt, alles andere passiert dann in ShowModal:
Delphi-Quellcode:
      repeat
        Application.HandleMessage;
        if Application.FTerminate then ModalResult := mrCancel else
          if ModalResult <> 0 then CloseModal;
      until ModalResult <> 0;
... und das hängt so lange in Application.HandleMessage, bis ich alle Daten eingelesen habe und damit die Prozedur beende.

Iwo Asnet 1. Dez 2011 11:49

AW: Tabelle/Query, die ihre Daten aus einer anderen Query bezieht
 
Eine live-Suche über eine Query lösen zu wollen, ist sportlich. I.a. werden die Daten schon geeignet im Speicher abgelegt, z.B. in einem Baum, Trie o.ä.

Als in-memory Kopie einer Tabelle würde ich eine in-memory Tabelle empfehlen :stupid: z.B. "kbMemTable" oder ein TClientDataset.

Ich würde allerdings würde die Daten wirklich einsaugen und in einer geeigneten Struktur ablegen. Ich kann mir vorstellen, das man alles in einen String klatscht, mit geeigneten Feld/Recordtrennern und dann ein sauschnelles Pos drüber laufen lässt.

Wonach soll denn überhaupt gesucht werden?

RSE 1. Dez 2011 12:22

AW: Tabelle/Query, die ihre Daten aus einer anderen Query bezieht
 
@Iwo Asnet:

Wenn du von Anfang an liest, wirst du feststellen, dass ich TClientDataSet ausgeschlossen habe incl. des Grundes. An die IBObjects als Zugriffmöglichkeit auf die DB bin ich gebunden, die setzen wir im ganzen Programm ein. Mein genannter Ansatz funktioniert inzwischen einwandfrei, damit habe ich meine Lösung gefunden.


Alle Zeitangaben in WEZ +1. Es ist jetzt 01:50 Uhr.

Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz