如何使用TClient数据集的日期过滤功能? [英] How to use the Filter functions of TClientdatasets for dates?
问题描述
CDS.Filter:= Edit1.Text;
CDS.Filtered:= True;
现在我查看Helpfile来过滤记录
,根据它我应该可以筛选日期时间字段以及。
但是每当我写这样的东西到我的编辑:
$ $ p $ code DAY(EDATUM)= 17
并应用过滤器我得到了表达式中的类型不匹配-Exception
我已经尝试了上面例子的许多不同的格式。
DATE(DAY(EDATUM))= DATE DAY(17))//不工作
DAY(EDATUM)='17'//不工作
DAY(EDATUM)= DAY(17)//不工作
DAY(EDATUM)= DAY(DATE('17 .09.2016'))
...
...
唯一有效的是
pre $ EDATUM = '17 .09.2016'// Works
但是我想单独过滤几个月和几年,而不是把它们放在一起。
我在其他地方找到的东西无论如何也没有。
任何想法我做错了什么?
Edatum是Firebird 1.5 Dat中的TimeStamp如果你想使用 Filter
表达式,而不是使用表达式,一个
OnFilterRecord
处理程序,值得看看TclientDataSet使用的 TExprParser
类的来源文本过滤器。它包含在Delphi源代码中的DBCommon.Pas单元文件中。 D7 TExprParser
支持以下功能:
函数TExprParser.TokenSymbolIsFunc const S:string):Boolean;
begin
结果:=(CompareText(S,'UPPER')= 0)或
(CompareText(S,'LOWER')= 0)或
[... (S,'DAY')= 0)或
(CompareText(S,'YEAR')= 0)或
(CompareText(S,'MONTH')= 0) )或
[...]
end;
顺便说一下,通过 TExprParser
的源代码,因为它显示了对SQL中找到的 IN
结构的支持。
(英国)系统,日期在DBGrid中显示为dd / mm / yyyy。鉴于此,下面显示的所有过滤器表达式都可以在D7中工作,而不会产生异常,并返回预期的结果:
$ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $>过程TForm1。 Button1Click(Sender:TObject);
begin
// CD的ADate字段由
// CDS1.FieldByName('ADate')初始化AsDateTime:= Now - random(365);
edFilter.Text:='ADate =''10 / 2/2017'''; //工作,日期格式= dd / mm / yyyy
edFilter.Text:='Month(ADate)= 2'; // works
edFilter.Text:='Year(ADate)= 2017'; //作品
edFilter.Text:='(Day(ADate)= 10)和(Year(ADate)= 2017)'; //作品
CDS1.Filtered:= False;
CDS1.Filter:= edFilter.Text;
CDS1.Filtered:= True;
end;
如果您没有得到类似的结果,我建议您先查看您的区域设置以及如何在TDBGrid中显示日期。
与其他筛选方法相比,筛选器表达式并不是特别有效,即使用 OnFilterRecord
事件。
在事件处理程序中,您可以使用例如将DecodeDateTime解码为年,月,日等组件,并将您喜欢的任何测试应用于其值。然后将接受
设置为True或False。
更新答案在这里
Delphi :检查DataSet的记录是否可见或被过滤
您遇到的问题是
TExprParser.TokenSymbolIsFunc()
不在用户的语言中。
您可以使用下面的代码来转换过滤器表达式中的日期函数名称。
查看嵌入式注释,了解它是如何工作的
$ b $ $ $ $ $ $ $ $ $ b $ TForm1 = class(TForm)
[...]
public
NameLookUp:TStringList;
[...]
end;
procedure TForm1.FormCreate(Sender:TObject);
begin
NameLookUp:= TStringList.Create;
//假设Y,M& C是本地语言名称
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;
解析器:TParser;
CH:Char;
begin
SS:= TStringStream.Create(Input);
解析器:= TParser.Create(SS);
结果:='';
尝试
CH:= Parser.Token;
//下面的翻译通过使用Classes.Pas中的TParser对Parser.Token<>中的
进行解析来实现输入。 #0 do begin
TokenText:= Parser.TokenString;
case
的情况下toSymbol:begin
//下面将转换符号
//的TokenText,但前提是TokenText不是ADataSet的字段名称
if ADataSet。 FindField(TokenText)= Nil然后开始
LookUpText:= NameLookUp.Values [TokenText];
如果LookUpText<> ''then
Result:= Result + LookUpText
else
Result:= Result + TokenText;
end
else
结果:=结果+ TokenText;
end;
toString:
//在输入中包含TokenText的单引号和嵌入其中的元素
//将被删除,因此恢复周围的元素和
//将嵌入的
Result:= Result +''''+ StringReplace(TokenText,'''','''''',[rfReplaceAll])+'''';
else
结果:=结果+ TokenText;
end; {case}
if Result<> ''然后
结果:=结果+'';
CH:= Parser.NextToken;
end;
终于
Parser.Free;
SS.Free;
end;
Log('TransResult',Result);
end;
procedure TForm1.btnSetFilterExprClick(Sender:TObject);
begin
//经过例如edFilter.Text测试=
// LastName ='aaa'和Y(BirthDate)= 2000
UpdateFilter2;
end;
程序TForm1.UpdateFilter2;
var
T1:Integer;
begin
CDS1.OnFilterRecord:= Nil;
T1:= GetTickCount;
CDS1.DisableControls;
尝试
CDS1.Filtered:= False;
CDS1.Filter:= TranslateExpression(edFilter.Text,CDS1);
if CDS1.Filter<> ''然后开始
CDS1.Filtered:= True;
end;
Log('Filter update time',IntToStr(GetTickCount - T1)+'ms');
终于
CDS1.EnableControls;
end;
end;
I have a TClientDataSet in Delphi 7 and I'd like to apply a filter which I type into a simple TEdit, so it looks like this:
CDS.Filter:=Edit1.Text;
CDS.Filtered:=True;
Now I looked at the Helpfile for filtering records and according to it I should be able to Filter DateTime-Fields as well. But whenever I write something like this into my Edit:
DAY(EDATUM)=17
and apply the filter I get a "Type Mismatch in Expression"-Exception.
I have tried numerous different formats of the example above.
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'))
...
...
the only one that works is
EDATUM='17.09.2016' //Works
But I want to filter on Days months and years seperately and not have them together in a string.
Nothing I found online elsewhere worked either.
Any Idea what I'm doing wrong?
Edatum is a TimeStamp in a Firebird 1.5 Database.
If you want to use a Filter
expression instead of an OnFilterRecord
handler, it is worthwhile taking a look at the source of the TExprParser
class, which is what TClientDataSet uses for textual filters. It is contained in the DBCommon.Pas unit file in your Delphi source. The D7 TExprParser
supports the following functions:
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;
Btw, it is worthwhile looking through the rest of TExprParser
's source because it reveals things like support for the IN
construct found in SQL.
On my (UK) system, dates display in a DBGrid as dd/mm/yyyy. Given that, all of the filter expressions shown below work in D7 without producing an exception and return the expected results:
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;
If you don't get similar results, I'd suggest you start by looking at your regional settings and how dates are displayed in a TDBGrid.
Filter expressions are not particularly efficient compared to the alternative method of filtering, namely to use the OnFilterRecord
event.
In the event handler, you can use e.g. DecodeDateTime
to decode it into its Year, Month, Day, etc components and apply whatever tests you like to their values. Then set Accept
to True or False.
Update I gather from your comment to an answer here
Delphi: check if Record of DataSet is visible or filtered
that the problem you had with this was that the date functions supported by
TExprParser.TokenSymbolIsFunc()
are not in your user's language.
You can use the code below to translate the date function names in the filter expression. See the embedded comments for explanation of how it works
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;
这篇关于如何使用TClient数据集的日期过滤功能?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!