delphijedi

TJvCsvDataSet and filter


I have a problem when it comes to filter a .csv file uploaded in TJvCsvDataSet. The following is a MCVE to explain

program Project3;

{$APPTYPE CONSOLE}

{$R *.res}

uses
  System.SysUtils,
  JvCsvData,
  data.DB;

var
  FJvCsvDataSet: TJvCsvDataSet;
I:Integer;
begin
  ;
  FJvCsvDataSet := TJvCsvDataSet.Create(nil);
  FJvCsvDataSet.CsvFieldDef :=
    'VTHB:%,VTHS:%,VTHBBP:&,VTBBSP:&,VTHBLP:&,VTHBLS:&,VTHTS:@';
  FJvCsvDataSet.FieldDefs.Add('VTHB', ftInteger, 0, False);
  FJvCsvDataSet.FieldDefs.Add('VTHS', ftInteger, 0, False);
  FJvCsvDataSet.FieldDefs.Add('VTHBBP', ftFloat, 0, False);
  FJvCsvDataSet.FieldDefs.Add('VTBBSP', ftFloat, 0, False);
  FJvCsvDataSet.FieldDefs.Add('VTHBLP', ftFloat, 0, False);
  FJvCsvDataSet.FieldDefs.Add('VTHBLS', ftFloat, 0, False);
  FJvCsvDataSet.FieldDefs.Add('VTHTS', ftDateTime, 0, False);

    FJvCsvDataSet.FileName :=
    'E:\...\abc.csv';
  FJvCsvDataSet.Open;
  FJvCsvDataSet.First;
//  FJvCsvDataSet.Sort('VTHB,VTHBBP', True);
  FJvCsvDataSet.Filtered := False;
  FJvCsvDataSet.Filter := '';
  for I := 1 to 1093 do
  begin
    FJvCsvDataSet.Filter:='VTHB=' + IntToStr(I);
    FJvCsvDataSet.Filtered := True;
  end;
  FJvCsvDataSet.Free;
end.

and the following is a sample of abc.csv uploaded by FJvCsvDataSet

VTHB,VTHS,VTHBBP,VTBBSP,VTHBLP,VTHBLS,VTHTS
1,1,3.05,279.86,3.1,115.98,2019-08-10 14:28:47.505
1,2,3.9,259.65,3.95,237.73,2019-08-10 14:28:47.52
1,3,3.9,136.48,3.95,31.97,2019-08-10 14:28:47.52
1,5,10.5,68.83,11,52.03,2019-08-10 14:28:47.52
1,4,12.5,41.4,13,47.75,2019-08-10 14:28:47.52
2,1,3.05,279.86,3.1,115.98,2019-08-10 14:28:47.863
2,2,3.9,259.65,3.95,237.73,2019-08-10 14:28:47.863
2,3,3.9,136.48,3.95,31.97,2019-08-10 14:28:47.863
2,5,10.5,68.83,11,52.03,2019-08-10 14:28:47.863
2,4,12.5,41.4,13,47.75,2019-08-10 14:28:47.863

When the statement FJvCsvDataSet.Filter:='VTHB=' + IntToStr(I); is executed FJvCsvDataSet.RecordCount does not change therefore the filter is not performed

What am I doing wrong ?


Solution

  • I don't think you are doing anything "wrong", it just seems to be that TJvCsvDataSet implements filtering in rather a strange way.

    Using your code to set up and open the dataset, the following code works fine and produces the expected records (observed in a DBGrid in a VCL version of your code):

    FJvCsvDataSet.SetFilterNum('VTHB', jfIntEqual, 1);
    FJvCsvDataSet.Filtered := True;
    

    This results in a FJvCsvDataSet.RecordCount of 5, as it should. This way of filtering uses the following enumeration as the second argument of SetFilterNum:

    TJvCsvFilterNumCompare = (jfIntEqual, jfIntNotEqual, jfLessThan, jfGreaterThan);
    

    However, doing this instead

    FJvCsvDataSet.Filter:= 'VTHB=1';
    

    produces incorrect results, namely no records are filtered out and a RecordCount of 10. Obviously something is going wrong, and I'll be back later to say if I've found out what it is.

    Update I've looked into it a bit further and there really is something rather strange going on.

    Just doing

    FJvCsvDataSet.Filter:= 'VTHB = 1';
    FJvCsvDataSet.Filtered := True;
    

    has no effect whatever, the dataset doesn't even scan the records to see if they match the filter. OTOH doing this

    FJvCsvDataSet.SetFilter('VTHB', '1');
    FJvCsvDataSet.Filtered := True;
    

    does result in the rows begin scanned, by the SetFilter method

    // string Filtering: Make Rows Visible Only if they match filterString
    procedure TJvCustomCsvDataSet.SetFilter(const FieldName: string; Pattern: string);
    

    and the rows are correct marked Filtered or not depending on whether they match the filter. However, at least two strange things:

    Update #2 Well, we can't say we weren't warned

    https://wiki.delphi-jedi.org/wiki/JVCL_Help:TJvCustomCsvDataSet.SetFilter

    says

    Note that this feature is NOT API-compatible with or similar to the filtering feature that is normally found in VCL TTable component.

    and the preceding description is couched in terms of filtering fields as character data, so I'm wondering whether it was ever intended to handle ftInteger fields ....