Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Programmieren allgemein (https://www.delphipraxis.net/40-programmieren-allgemein/)
-   -   Delphi TQuery/TTable filtern ohne Daten neu abzurufen (https://www.delphipraxis.net/180492-tquery-ttable-filtern-ohne-daten-neu-abzurufen.html)

Nils S. 23. Mai 2014 11:57

TQuery/TTable filtern ohne Daten neu abzurufen
 
Guten Tag zusammen,

wenn man bei einem Query oder Table den Filter setzt (
Delphi-Quellcode:
Table1.Filter := 'Column1 = abc';
), wird die Datenmenge, welche die Komponente abrufen soll, neu abgerufen (mit einer Where-Klausel o.ä.) oder nicht?
Wenn dem so ist, würde das die Performance bei größeren Datenmengen wohl stark beeinflussen.
Gibt es eine Möglichkeit, dass einfach nur die vorhandene Datenmenge der Komponente gefiltert und angezeigt wird ohne, dass die Daten neu abgerufen werden?

MrSpock 23. Mai 2014 12:08

AW: TQuery/TTable filtern ohne Daten neu abzurufen
 
Ich war bisher der Meinung, dass keine neue Abfrage an die DB geschickt wird, sondern, dass der Filter auf die abgerufene Datenmenge angewendet wird.

Der schöne Günther 23. Mai 2014 12:15

AW: TQuery/TTable filtern ohne Daten neu abzurufen
 
Filter ist noch nur von TDataSet vorgegeben, wie die konkrete Implementierung aussieht, kann wahrscheinlich jede Implementierung (FireDAC, dbExpress, ...) selbst entscheiden, oder?

Das hätte ich jetzt geraten ohne irgendetwas zu prüfen...

Nils S. 23. Mai 2014 12:19

AW: TQuery/TTable filtern ohne Daten neu abzurufen
 
Also in meinem Fall handelt es sich um FireDAC Komponenten.
Ich habe mal was gehört von server- und clientseitigem Filter.
Finden kann ich unter diesen Begriffen aber nichts.

rokli 23. Mai 2014 12:24

AW: TQuery/TTable filtern ohne Daten neu abzurufen
 
Kannst Du den sicherstellen, dass sich zwischendurch nichts geändert hat?

Wenn nicht, dann wäre es nicht sinnvoll, wenn Du nur in den bereits gelesenen Daten filtern würdest.

Moin

Der schöne Günther 23. Mai 2014 13:12

AW: TQuery/TTable filtern ohne Daten neu abzurufen
 
FireDAC verweist auf die Data.DB-Grundphilosophie.

Zitat:

Anmerkung: Wenn die Filterung aktiviert ist und der Benutzer einen Datensatz bearbeitet, kann dies dazu führen, dass der Datensatz die Filterbedingungen nicht mehr erfüllt. Beim nächsten Abrufen von Datensätzen aus der Datenmenge anhand des Filters ist ein solcher Datensatz dann "verschwunden". Der nächste Datensatz, der die Bedingungen erfüllt, wird dann zum aktuellen.
Also ich würde so rauslesen, dass ein Ändern der Filter nicht aktiv wird und nochmals Queries absetzt...

Perlsau 23. Mai 2014 14:20

AW: TQuery/TTable filtern ohne Daten neu abzurufen
 
Zitat:

Zitat von Nils S. (Beitrag 1259930)
wenn man bei einem Query oder Table den Filter setzt (
Delphi-Quellcode:
Table1.Filter := 'Column1 = abc';
), wird die Datenmenge, welche die Komponente abrufen soll, neu abgerufen (mit einer Where-Klausel o.ä.) oder nicht?

Läßt sich doch ganz einfach testen:
Du programmierst dir eine Methode zum Setzen bzw. Löschen des Filters:
Delphi-Quellcode:

private {private Deklarationen}

Procedure TFormMain.Filtern(MyTable : TTable; MyFilter : String; Setzen : Boolean);
begin
  MyTable.Filtered := False;

  if Setzen then
  begin
    MyTable.Filter := MyFilter;
    MyTable.Filtered := True;
  end;
end;
Die rufst du – meinetwegen mit einem Buttonklick – auf, nachdem du mit deinem Lieblings-Datenbank-Manager einen Wert in dieser Tabelle geändert hast. Wird der geänderte Wert auch in deiner Anwendung angezeigt, hat das Setzen des Filters aktuelle Daten aus der DB geschaufelt, andernfalls nicht.

Nils S. 24. Mai 2014 07:43

AW: TQuery/TTable filtern ohne Daten neu abzurufen
 
Zitat:

Zitat von Perlsau (Beitrag 1259957)
Zitat:

Zitat von Nils S. (Beitrag 1259930)
wenn man bei einem Query oder Table den Filter setzt (
Delphi-Quellcode:
Table1.Filter := 'Column1 = abc';
), wird die Datenmenge, welche die Komponente abrufen soll, neu abgerufen (mit einer Where-Klausel o.ä.) oder nicht?

Läßt sich doch ganz einfach testen:
Du programmierst dir eine Methode zum Setzen bzw. Löschen des Filters:
Delphi-Quellcode:

private {private Deklarationen}

Procedure TFormMain.Filtern(MyTable : TTable; MyFilter : String; Setzen : Boolean);
begin
  MyTable.Filtered := False;

  if Setzen then
  begin
    MyTable.Filter := MyFilter;
    MyTable.Filtered := True;
  end;
end;
Die rufst du – meinetwegen mit einem Buttonklick – auf, nachdem du mit deinem Lieblings-Datenbank-Manager einen Wert in dieser Tabelle geändert hast. Wird der geänderte Wert auch in deiner Anwendung angezeigt, hat das Setzen des Filters aktuelle Daten aus der DB geschaufelt, andernfalls nicht.

Das habe ich mir auch kurz nach dem Erstellen gedacht und gemacht.
Habe nun festgestellt, dass bei einem Filter die Daten aus der Datenbank neu abgerufen werden.

Perlsau 24. Mai 2014 07:47

AW: TQuery/TTable filtern ohne Daten neu abzurufen
 
Zitat:

Zitat von Nils S. (Beitrag 1260053)
Habe nun festgestellt, dass bei einem Filter die Daten aus der Datenbank neu abgerufen werden.

Siehst du – geht doch :thumb:

Und wenn du nicht willst, daß beim Filtern die Datenmenge neu abgerufen wird, verwendest du ein TClientDataset oder ein TMemoryDataSet, das zum Zeitpunkt der Filtersetzung keine Verbindung zur Datenbank besitzt, was bei großen Datenmengen selbstverständlich entsprechende Speicherkapazitäten voraussetzt.

Der schöne Günther 24. Mai 2014 09:26

AW: TQuery/TTable filtern ohne Daten neu abzurufen
 
Geprüft habe ich es jetzt selbst noch nicht, aber das hätte ich jetzt nicht erwartet! :oops:

Ich hatte mehr aus Interesse einfach mal nicht die Query angepasst, sondern mal mit der Filter-Einstellung gespielt.

Wenn es um ein paar GB geht ist ein Memory-Dataset bei mir allerdings auch keine Option mehr :lol:
Ich glaube, ich lasse die ganze Filter-Geschichte einfach sein...

Perlsau 24. Mai 2014 09:29

AW: TQuery/TTable filtern ohne Daten neu abzurufen
 
Zitat:

Zitat von Der schöne Günther (Beitrag 1260064)
Wenn es um ein paar GB geht ist ein Memory-Dataset bei mir allerdings auch keine Option mehr :lol:
Ich glaube, ich lasse die ganze Filter-Geschichte einfach sein...

Du entwickelst doch mit XE5, da kann man doch wunderbar 64-Bit-Anwendungen compilieren, und wenn du wie heute üblich mind. 8 oder besser gleich 16 oder 32 GB Arbeitsspeicher hast, passen da die allermeisten Tabellen doch locker rein :wink:

Dejan Vu 24. Mai 2014 10:33

AW: TQuery/TTable filtern ohne Daten neu abzurufen
 
Man liest keine GB an Daten in den Speicher. Wozu? Wer soll sich das anschauen?

Ich würde noch mit dem 'OnFilterRecord'-Event herumspielen, das finde ich flexibler und es wäre denkbar, das die Daten dann doch nicht mehrfach geladen werden. Ich kann mir das auch nicht vorstellen, ehrlich gesagt.

Zeig mal den Code, mit dem Du das testest.

Ich lass mich gerne überzeugen. :)

Edit: Ich habe das hier mal (allerdings mit ADO) nachgestellt. Die Daten werden *nicht* neu geladen, wenn ich das Filtern umstelle:
Delphi-Quellcode:
Procedure TForm1.Button1Click(Sender : TObject)
Begin
  myDataset.Filtered := not myDataSet.Filtered;
End;
Aber klar, ADO != FireDAC. (Und TDataSet.SetFiltered ist virtual).

Nils S. 24. Mai 2014 11:28

AW: TQuery/TTable filtern ohne Daten neu abzurufen
 
Also wenn ich .Filter := ... setze, werden immer die aktuellen Daten aus der Datenbank angezeigt.
Hier ist der Code:
Delphi-Quellcode:
procedure SetTblUserFilter;
begin
  with UserDat.tblUser do
  begin
    Close;
    Filter :=
      ('lower(LAST_NAME) like ''%' +
      AnsiLowerCase(UserSettingsFrm.edtSearchUser.Text) + '%''' +
      ' or lower(FIRST_NAME) like ''%' +
      AnsiLowerCase(UserSettingsFrm.edtSearchUser.Text) + '%''' +
      ' or lower(LOGIN_NAME) like ''%' +
      AnsiLowerCase(UserSettingsFrm.edtSearchUser.Text) + '%''');
    Open;
  end;
Filtered ist standardmäßig auf True gesetzt.
Das Close und Open verwende ich, da es sonst teilweise zu merkwürdigen Anzeigefehlern im Grid kommt,
wo wir schonmal dabei sind, ist das auch schonm Mal jemandem aufgefallen? Arbeite mit XE5, Firemonkey.
Ich habe es aber natürlich auch ohne Open und Close getestet und jedes mal, wenn der Filter geändert wird,
werden die aktuellen Daten aus der Datenbank angezeigt.

Dejan Vu 24. Mai 2014 13:50

AW: TQuery/TTable filtern ohne Daten neu abzurufen
 
Das liegt an dem 'Open' und nicht am Filter.
Ich würde das mit dem Verändern des Filters vielleicht mal so probieren

Delphi-Quellcode:
myDataSet.DisableControls;
Try
  myDataSet.Filtered := False;
  myDataSet.Filter := CreateMyNewFilter();
  myDataSet.Filtered := True;
Finally
  myDataSet.EnableControls;
end;
Vielleicht kann man das Problem damit Umschiffen. Das sieht mir nämlich nach einem Refresh-Problem im FMX-Framework aus.

Nils S. 24. Mai 2014 13:57

AW: TQuery/TTable filtern ohne Daten neu abzurufen
 
Wie gesagt, das Close und Open habe ich nach dem Test hinzugefügt, wegen des Anzeigefehlers.
Und Du meinst Filtered auf False/True setzen macht einen Unterschied?

Kann ich mir noch nicht so ganz vorstellen aber ich werde das später mal ausprobieren.

Dejan Vu 24. Mai 2014 14:03

AW: TQuery/TTable filtern ohne Daten neu abzurufen
 
Zitat:

Zitat von Nils S. (Beitrag 1260092)
Und Du meinst Filtered auf False/True setzen macht einen Unterschied?
Kann ich mir noch nicht so ganz vorstellen aber ich werde das später mal ausprobieren.

... Ich auch nicht, wenn ich darüber nachdenke. :oops:

Perlsau 24. Mai 2014 17:11

AW: TQuery/TTable filtern ohne Daten neu abzurufen
 
Zitat:

Zitat von Nils S. (Beitrag 1260092)
Und Du meinst Filtered auf False/True setzen macht einen Unterschied?

Das ist die normale Vorgehensweise beim Setzen eines neuen Filters. Genau dafür gibt es das Filtered-Property.

Dejan Vu 24. Mai 2014 17:16

AW: TQuery/TTable filtern ohne Daten neu abzurufen
 
Zitat:

Zitat von Perlsau (Beitrag 1260101)
Wenn du den Filter-String bei gesetztem Filtered-Property (filtered := true) änderst, passiert gar nichts.

Das dachte ich auch, bis ich es eben ausprobiert habe (Mit ADO). Aber da SetFilterText auch virtual ist, dürfte das individuell und unterschiedlich sein. Daher: Ausprobieren.

Perlsau 24. Mai 2014 17:29

AW: TQuery/TTable filtern ohne Daten neu abzurufen
 
Zitat:

Zitat von Dejan Vu (Beitrag 1260103)
Zitat:

Zitat von Perlsau (Beitrag 1260101)
Wenn du den Filter-String bei gesetztem Filtered-Property (filtered := true) änderst, passiert gar nichts.

Das dachte ich auch, bis ich es eben ausprobiert habe (Mit ADO). Aber da SetFilterText auch virtual ist, dürfte das individuell und unterschiedlich sein. Daher: Ausprobieren.

Hast du den Filter bei aktivem Dataset und gesetztem Filtered-Property lediglich im Objekt-Inspektor geändert? In dem Fall änders sich auch bei mir die Filtermenge oder, anders ausgedrückt, bei Enter in der OI-Zelle mit dem neuen Filterwert wird der Filter gesetzt und aktiviert. Mache ich dasselbe jedoch im Code, passiert absolut gar nichts:
Delphi-Quellcode:
  IF DatMod.V_Messung.Filter = '' THEN
     DatMod.V_Messung.Filter := 'M_WERT < 100' ELSE
     DatMod.V_Messung.Filter := '';

     StatBarMain.Panels[3].Text := DatMod.V_Messung.Filter;
Erst ein Ausschalten des Filters und darauf folgendes Einschalten aktiviert hier den Filter. (getestet mit IbDac und Firebird)

Dejan Vu 24. Mai 2014 17:39

AW: TQuery/TTable filtern ohne Daten neu abzurufen
 
Ich habe als Test eine Tabelle mit einer Spalte, die 5 unterschiedlicher Werte annehmen kann, genommen. Dann einen Button auf die Form und im Buttonclick:

Delphi-Quellcode:
Procedure TForm.ButtonClick(Sender : TObject);
Begin
  id := id mod 5 + 1;
  myDataSet.Filter := 'ColumnType = '+intToStr(id);
end;
Dann noch ein Grid, ein Dataset, mit der Datenbank verbunden und los. Nun klicke ich auf den Button und sehe im Grid nacheinander jeweils die Einträge mit 'ColumnType=1', 'ColumnType=2' usw.

Funktioniert also. Dann habe ich das so geändert, das ich noch id=6 nehme und dann den Filtertext leere, also so:
Delphi-Quellcode:
Procedure TForm.ButtonClick(Sender : TObject);
Begin
  id := id mod 6 + 1;
  if id=6 then
    myDataSet.Filter := ''
  else
    myDataSet.Filter := 'ColumnType = '+intToStr(id);
end;
Funzt auch.

Perlsau 24. Mai 2014 18:39

AW: TQuery/TTable filtern ohne Daten neu abzurufen
 
Du hast recht: auch bei mir mit IbDac und Firebird läuft das so, ebenso mit Ado und MsSQL. Ich hatte beim ersten Testen nicht daran gedacht, Filtered zuvor auf True zu setzen und daher ein falsches Testergebnis erhalten. Und die Datenmenge muß aus gutem Grund jedesmal neu eingelesen werden, wenn der Filter sich ändert, denn der Filter legt fest, was sich in der Datenmenge befindet: Ausgefilterte Datensätze sind nicht Teil der Datenmenge.

Dejan Vu 25. Mai 2014 08:14

AW: TQuery/TTable filtern ohne Daten neu abzurufen
 
Wenns bei IbDac so läuft, dann postuliere ich, das das mit FireDac auch geht. Ergo liegt ein Refresh-Problem im FMX-Framework vor. Wenn der Fragesteller mit einer TListView arbeitet, wird er das Refresh wohl selber vornehmen... Das könnte die Ursache sein.

Nils: Mehr Code! ;-)

Nils S. 25. Mai 2014 09:20

AW: TQuery/TTable filtern ohne Daten neu abzurufen
 
Also ich habe das natürlich auch gerade mal ausprobiert mit Filtered := False/True.
Auch da wird der aktuelle Datensatz aus der Datenbank gelesen und angezeigt.
Aber wenn ich den letzten Teil der Disskusion jetzt richtig verstanden habe, ist das so ja der Normalfall.
Zitat:

Zitat von Perlsau (Beitrag 1260106)
Du hast recht: auch bei mir mit IbDac und Firebird läuft das so, ebenso mit Ado und MsSQL. Ich hatte beim ersten Testen nicht daran gedacht, Filtered zuvor auf True zu setzen und daher ein falsches Testergebnis erhalten. Und die Datenmenge muß aus gutem Grund jedesmal neu eingelesen werden, wenn der Filter sich ändert, denn der Filter legt fest, was sich in der Datenmenge befindet: Ausgefilterte Datensätze sind nicht Teil der Datenmenge.

Also erstmal kein Refresh Problem mit FMX. (Oder bringe ich jetzt etwas durcheinander?)

Meine ursprüngliche Frage ist ja, wie man dieses Refreshen umgehen kann um den Programmablauf bei großen Datenmengen zu beschläunigen.
Mittlerweile bin ich mir gar nicht mehr sicher ob ich das überhaupt machen will, weil sich ja, wie zuvor auch schon erwähnt wurde, die Daten geändert haben könnten.

Dejan Vu 25. Mai 2014 09:38

AW: TQuery/TTable filtern ohne Daten neu abzurufen
 
NEIN! Es ist *nicht* normal, das bei verändern der Filter-Eigenschaft die Daten neu gelesen werden.
Du hast doch immer noch 'Close/Open' im Code, oder?

Perlsau 25. Mai 2014 10:43

AW: TQuery/TTable filtern ohne Daten neu abzurufen
 
Kann ich zumindest für Ado-Dataset auf MsSQL zugreifend bestätigen: Habe eben im Server Manager einen Wert geändert und danach den Filter im bereits verbundenen (Active = True) Ado-Dataset gesetzt mit dem Resultat, daß weiterhin der alte Wert in der betreffenen Spalte angezeigt wurde. Demnach filtert Ado wohl nur die eigene Datenmenge und nicht die in der DB vorhandene. Erst ein Open/Close des Datasets bringt den geänderten Wert zur Ansicht z.B. im DBGrid.

Seltsamerweise erhalte ich beim Versuch, statt Open/Close ein Refresh auszuführen, diese Fehlermeldung:

' Nicht genügend Basistabelleninformationen zum Aktualisieren '

Wie sich das bei anderen DB-Komponenten, noch dazu unter FMX verhält, läßt sich mit Sicherheit ermitteln. Aber ich gehe mal davon aus, daß es sich hier um ein Standard-Verhalten handelt, von dem seriöse Anbieter von DB-Komponenten nicht abweichen.

Delphi-Quellcode:
procedure TFormMain.FilterTest;
Var
 Id : Integer;
begin
  Id := DatMod.Tab_VDateien.FieldByName('Id_Video').AsInteger;
  IF DatMod.Tab_VDateien.Filter = '' THEN
     DatMod.Tab_VDateien.Filter := 'Jahr = 1960' ELSE
     DatMod.Tab_VDateien.Filter := '';

// Dieser Befehl führt zu besagter Fehlermeldung:
//  DatMod.Tab_VDateien.Refresh;

// Damit werden auch zwischenzeitlich geänderte Daten korrekt angezeigt:
  DatMod.Tab_VDateien.Close;
  DatMod.Tab_VDateien.Open;
  DatMod.Tab_VDateien.Locate('Id_Video',Id,[]);
end;

Dejan Vu 25. Mai 2014 10:46

AW: TQuery/TTable filtern ohne Daten neu abzurufen
 
Für ein Refresh musst Du dem Dataset einen eindeutigen Schlüssel spendieren. Glaube ich.

Nils S. 25. Mai 2014 11:06

AW: TQuery/TTable filtern ohne Daten neu abzurufen
 
Nein, auch ohne ein Close und Open wird die Datenmenge neu abgerufen.

Perlsau 25. Mai 2014 11:09

AW: TQuery/TTable filtern ohne Daten neu abzurufen
 
Liste der Anhänge anzeigen (Anzahl: 1)
Zitat:

Zitat von Dejan Vu (Beitrag 1260152)
Für ein Refresh musst Du dem Dataset einen eindeutigen Schlüssel spendieren. Glaube ich.

Schlüssel? Dataset? Was für ein Schlüssel? Meinst du, man benötigt in der Tabelle einen PK, um ein Refresh ausführen zu können? Der ist natürlich vorhanden: ID_Video.

Auch ein Ändern des Cursotypes im Dataset von ctStatic auf ctDynamic hat nicht die in der Online-Hilfe angekündigte Wirkung, denn der zuvor via DB-Manager geänderte Wert wird auch hier ohne nachstehendes Open/Close nicht angezeigt:

ctDynamic: Dynamischer Cursor. Die von anderen Benutzern hinzugefügten, geänderten und gelöschten Daten werden angezeigt. Die Datensätze können in beiden Richtungen durchlaufen werden.
ctStatic: Statischer Cursor. Eine statische Kopie der Datensätze. Die von anderen Benutzern geänderten Daten werden nicht angezeigt. Diese Cursor-Art wird hauptsächlich für Berichte verwendet.

Hat wohl mit der darunterstehenden Anmerkung zu tun: Wenn die Eigenschaft CursorLocation der ADO-Datenmenge den Wert clUseClientOnly hat, wird nur die Konstante ctStatic unterstützt. Und tatsächlich, clUseServer wird von diesem Provider nicht unterstützt, wie Delphi beim Start der Anwendung meldet, wenn ich die CursorLocation zuvor auf clUseClient (clUseClientOnly gibt's bei mir nicht) umgestellt habe:

' Das aktuelle Recordset unterstützt keine Lesezeichen. Hierbei handelt es sich möglicherweise um eine Einschränkung seitens des Providers oder des gewählten Cursortyps '

Zitat:

Zitat von Nils S. (Beitrag 1260158)
Nein, auch ohne ein Close und Open wird die Datenmenge neu abgerufen.

In meinem dargestellten Fall definitiv nicht. Wie hast du das überprüft? Wenn du richtig getestet hast, dann verhalten sich diverse DB-Komponenten diesbezüglich unterschiedlich.


Alle Zeitangaben in WEZ +1. Es ist jetzt 00:55 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