2017-02-10 6 views
0

私は、Delphi 7でTClientDataSetのを持っており、それは次のようになりますので、私は、私はシンプルTEDITに入力フィルタを適用したいと思います:日付のTClientdatasetsのフィルタ関数の使用方法

CDS.Filter:=Edit1.Text; 
CDS.Filtered:=True; 

を今、私はフィルタリングレコード のためにヘルプファイルを見て、それによるとDateTime-Fieldsもフィルタリングできるはずです。 しかし、時はいつでも、私は私の編集には、このような何かを書く:

DAY(EDATUM)=17 

と私は、「式で型が一致しません」-Exceptionを取得し、フィルタを適用します。

私は上記の例の数多くの異なるフォーマットを試しました。

DATE(DAY(EDATUM))=DATE(DAY(17))  //Doesn't work 
DAY(EDATUM)='17'     //Doesn't work 
DAY(EDATUM)=DAY(17)     //Doesn't work 
DAY(EDATUM)=DAY(DATE('17.09.2016')) 
... 
... 

作品だけは

EDATUM='17.09.2016'     //Works 

あるしかし、私は別々日月と年にフィルタリングして、文字列にそれらを一緒に持っていたいです。

他の場所でオンラインで見つかったものはありませんでした。

私が間違っていることは何ですか?

Edatumは、Firebird 1.5データベースのタイムスタンプです。

+0

をどのように動作するかの説明については、埋め込まれたコメントを参照してください:...... edatumの月(抽出、edatum_dayとして(edatumの日)を抽出)edatum_monthとして、edatum_yearとして(edatumの年)を抽出するので、これらのフィールドを非常に簡単にフィルタリングできるようになりましたか? –

+0

タイトルのタグ情報を繰り返す必要はありません。 –

答えて

7

あなたはFilter表現の代わりに、OnFilterRecordハンドラを使用したい場合は、TClientDataSetには、テキストフィルタに使用するものであるTExprParserクラスのソースを見てみ価値があります。これは、Delphiソース内のDBCommon.Pasユニットファイルに含まれています。 D7 TExprParserは、次の機能をサポートしています。

function TExprParser.TokenSymbolIsFunc(const S: string) : Boolean; 
begin 
    Result := (CompareText(S, 'UPPER') = 0) or 
      (CompareText(S, 'LOWER') = 0) or 
      [...] 
      (CompareText(S, 'YEAR') = 0) or 
      (CompareText(S, 'MONTH') = 0) or 
      (CompareText(S, 'DAY') = 0) or 
      [...] 
end; 

ところで、それはそれはSQLで見つかったIN構築物についてのサポートのようなものを明らかにするためTExprParserのソースの残りを見て価値があります。

私の(イギリス)システムでは、日付はDBGridにdd/mm/yyyyとして表示されます。例外を発生させずにフィルター式の全てがD7での作業の下に示し、ことを考えると、期待される結果を返す:あなたが同様の結果を得られない場合は

procedure TForm1.Button1Click(Sender: TObject); 
begin 

    // ADate field of CDS is initialised by 
    // CDS1.FieldByName('ADate').AsDateTime := Now - random(365); 

    edFilter.Text := 'ADate = ''10/2/2017'''; // works, date format = dd/mm/yyyy 
    edFilter.Text := 'Month(ADate) = 2';  // works 
    edFilter.Text := 'Year(ADate) = 2017';  // works 
    edFilter.Text := '(Day(ADate) = 10) and (Year(ADate) = 2017)';  // works 

    CDS1.Filtered := False; 
    CDS1.Filter := edFilter.Text; 
    CDS1.Filtered := True; 
end; 

、私はあなたがあなたの地域を見てから始めることをお勧めしたいですTDBGridに日付を表​​示する方法について説明します。

フィルタ式は、フィルタリングの代替方法、つまりOnFilterRecordイベントを使用する場合に比べて特に効率的ではありません。

イベントハンドラでは、たとえばDecodeDateTimeを入力してYear、Month、Dayなどのコンポーネントにデコードし、好きなテストをその値に適用します。次に、AcceptをTrueまたはFalseに設定します。

更新は、私はあなたがこのとしていた問題は TExprParser.TokenSymbolIsFunc()でサポートされている日付関数は、ユーザーの言語ではないということであったことをここに答え Delphi: check if Record of DataSet is visible or filtered にあなたのコメントから集まります。

以下のコードを使用して、フィルタ式の日付関数名を変換することができます。 それはなぜあなたはあなたのクエリに3つの隠された列を追加していない

type 
    TForm1 = class(TForm) 
    [...] 
    public 
    NameLookUp : TStringList; 
    [...] 
    end; 

procedure TForm1.FormCreate(Sender: TObject); 
begin 
    NameLookUp := TStringList.Create; 
    // Assume Y, M & C are the local-language names 
    NameLookUp.Add('Y=Year'); 
    NameLookUp.Add('M=Month'); 
    NameLookUp.Add('D=Day'); 
    [...] 
end; 

procedure TForm1.Log(const Title, Msg : String); 
begin 
    Memo1.Lines.Add(Title + ' : ' + Msg); 
end; 

function TForm1.TranslateExpression(const Input : String; ADataSet : TDataSet) : String; 
var 
    SS : TStringStream; 
    TokenText : String; 
    LookUpText : String; 
    Parser : TParser; 
    CH : Char; 
begin 
    SS := TStringStream.Create(Input); 
    Parser := TParser.Create(SS); 
    Result := ''; 
    try 
    CH := Parser.Token; 
    // following translates Input by parsing it using TParser from Classes.Pas 
    while Parser.Token <> #0 do begin 
     TokenText := Parser.TokenString; 
     case CH of 
     toSymbol : begin 
      // The following will translate TokenText for symbols 
      // but only if TokenText is not a FieldName of ADataSet 
      if ADataSet.FindField(TokenText) = Nil then begin 
      LookUpText := NameLookUp.Values[TokenText]; 
      if LookUpText <> '' then 
       Result := Result + LookUpText 
      else 
       Result := Result + TokenText; 
      end 
      else 
      Result := Result + TokenText; 
     end; 
     toString : 
      // SingleQuotes surrounding TokenText in Input and ones embedded in it 
      // will have been stripped, so reinstate the surrounding ones and 
      // double-up the embedded ones 
     Result := Result + '''' + StringReplace(TokenText, '''', '''''', [rfReplaceAll]) + ''''; 
     else 
      Result := Result + TokenText; 
     end; { case } 
     if Result <> '' then 
     Result := Result + ' '; 
     CH := Parser.NextToken; 
    end; 
    finally 
    Parser.Free; 
    SS.Free; 
    end; 
    Log('TransResult', Result); 
end; 

procedure TForm1.btnSetFilterExprClick(Sender: TObject); 
begin 
    // Following tested with e.g edFilter.Text = 
    // LastName = 'aaa' and Y(BirthDate) = 2000 
    UpdateFilter2; 
end; 

procedure TForm1.UpdateFilter2; 
var 
    T1 : Integer; 
begin 
    CDS1.OnFilterRecord := Nil; 
    T1 := GetTickCount; 
    CDS1.DisableControls; 
    try 
    CDS1.Filtered := False; 
    CDS1.Filter := TranslateExpression(edFilter.Text, CDS1); 
    if CDS1.Filter <> '' then begin 
     CDS1.Filtered := True; 
    end; 
    Log('Filter update time', IntToStr(GetTickCount - T1) + 'ms'); 
    finally 
    CDS1.EnableControls; 
    end; 
end; 
+0

私は本当にこの1つのOnFilterRecordメソッドを避けることを望んだ –

+0

なぜそれについて心配しますか?これは、CDSが式パー​​サを構築し、それを非効率的に各行に適用するオーバーヘッドを回避します。輸送のための – MartynA

+0

。 –

関連する問題