在下面的tFDMemTable中,我尝试对ID字段以字母A开头的记录的值求和。A1,A2和结果应为4。
type
TForm1 = class(TForm)
FDMemTable1: TFDMemTable;
DBGrid1: TDBGrid;
DataSource1: TDataSource;
Button1: TButton;
Button2: TButton;
procedure FormCreate(Sender: TObject);
procedure Button1Click(Sender: TObject);
procedure Button2Click(Sender: TObject);
end;
procedure TForm1.FormCreate(Sender: TObject);
var
_FieldDef: TFieldDef;
begin
_FieldDef := FDMemTable1.FieldDefs.AddFieldDef;
_FieldDef.Name := 'ID';
_FieldDef.DataType := ftString;
_FieldDef.Size := 5;
_FieldDef := FDMemTable1.FieldDefs.AddFieldDef;
_FieldDef.Name :='value';
_FieldDef.DataType := ftInteger;
FDMemTable1.CreateDataSet;
FDMemTable1.Append;
FDMemTable1.FieldValues['ID'] := 'A1';
FDMemTable1.FieldValues['value'] := 1;
FDMemTable1.Append;
FDMemTable1.FieldValues['ID'] := 'B1';
FDMemTable1.FieldValues['value'] := 2;
FDMemTable1.Append;
FDMemTable1.FieldValues['ID'] := 'A2';
FDMemTable1.FieldValues['value'] := 3;
FDMemTable1.Append;
FDMemTable1.FieldValues['ID'] := 'B2';
FDMemTable1.FieldValues['value'] := 4;
end;
我编写了以下代码,但将tDBGrid更改为已过滤。我想要的只是一个内部过程,tDBGrid应该保持不变。
procedure TForm1.Button1Click(Sender: TObject);
var
_ValueSum: Integer;
i: Integer;
begin
FDMemTable1.Filter := 'ID like ' + QuotedStr('A%');
FDMemTable1.Filtered := True;
_ValueSum := 0;
FDMemTable1.FindFirst;
for i := 0 to FDMemTable1.RecordCount - 1 do
begin
_ValueSum := _ValueSum + FDMemTable1.FieldValues['value'];
FDMemTable1.FindNext;
end;
Button1.Caption := IntToStr(_ValueSum);
end;
我知道tDataSet.Locate不允许我尝试像这样的原始方式进行下一次搜索。它工作正常,但看起来有点愚蠢。
procedure TForm1.Button2Click(Sender: TObject);
var
_ValueSum: Integer;
i: Integer;
begin
_ValueSum := 0;
FDMemTable1.First;
for i := 0 to FDMemTable1.RecordCount do
begin
if Copy(FDMemTable1.FieldValues['ID'], 1, 1) = 'A' then
begin
_ValueSum := _ValueSum + FDMemTable1.FieldValues['value'];
end;
FDMemTable1.FindNext;
end;
Button2.Caption := IntToStr(_ValueSum);
end;
当我断开tFDMemTable和tDBGrid的连接或在过滤以保持最后一个网格状态之前将其设置为非活动状态时,网格将变为空白。最后的代码是最好的解决方案,还是有什么更好的方法可以显示在过滤工作时未过滤的结果?
答案 0 :(得分:5)
有些事情,如果不是“错误的”,则与您的代码不太相符。
您应该使用Next
而不是FindNext
移到数据集中的下一行。 Next
移至数据集中的下一行,而FindNext
移至与您已设置的搜索条件相匹配的下一行,例如使用DataSet.SetKey; ...
-阅读FindKey
用法在线帮助。
您不应该尝试使用For
循环遍历数据集。使用While not FDMemData.Eof do
循环。 Eof
代表“文件尾”,一旦数据集位于最后一行,则返回true。
您应该在循环之前调用FDMemTable1.DisableControls
,在循环之后调用FDMemTable1.EnableControls
。这样可以防止像DBGrid这样的数据库感知控件在循环内部进行更新,否则将在网格更新时降低循环速度。
除非您有充分的理由不这样做,否则请始终以与设置数据集相同的方法清除数据集过滤器,否则,如果您忘记了过滤器处于活动状态,则会出现一些非常混乱的错误。
在绝对不需要时,请尝试避免使用RecordCount
。取决于您使用的RDMS,它可能导致服务器和网络上许多可避免的处理开销(由于某些服务器类型,它将导致将整个数据集检索到客户端)。
将您的第一个循环更改为
procedure TForm1.Button1Click(Sender: TObject);
var
_ValueSum : Integer;
begin
_ValueSum := 0;
FDMemTable1.Filter := 'ID like ' + QuotedStr('A%');
try
FDMemTable1.DisableControls;
FDMemTable1.First;
while not FDMemTable1.Eof do begin
_ValueSum:= _ValueSum + FDMemTable1.FieldByName('Value').AsInteger;
FDMemTable1.Next;
end
finally
FDMemTable1.Filter := '';
FDMemTable1.Filtered := False;
FDMemTable1.EnableControls;
end;
Button1.Caption := IntToStr(_ValueSum);
end;
如果这样做,则完全不需要Button2Click方法。
如注释中所述,您可以使用TBookMark在循环之前记录您在数据集中的位置,然后在循环中返回,如
var
_ValueSum : Integer;
BM : TBookMark;
begin
_ValueSum := 0;
BM := FDMemTable.GetBookMark;
FDMemTable1.Filter := 'ID like ' + QuotedStr('A%');
try
[etc]
finally
FDMemTable1.Filter := '';
FDMemTable1.Filtered := False;
FDMemTable1.GotoBookMark(BM);
FDMemTable1.FeeBookMark(BM);
FDMemTable1.EnableControls;
end;
通过使用InsertRecord
方法,您可以节省一些键入内容,并获得更简洁的代码
FDMemTable1.InsertRecord(['A1', 1]);
FDMemTable1.InsertRecord(['B1', 2]);
FDMemTable1.InsertRecord(['A2', 3]);
FDMemTable1.InsertRecord(['B2', 4]);
Btw#2:使用FindKey
的时间是在设置要查找的键之后,通过调用SetKey
而不是设置键值来进行。
对于数据集的常规导航,请使用标准导航方法,例如Next
,Prior
,First
,Last
,MoveBy
等。
答案 1 :(得分:3)
FireDAC还有一个有趣的选项-聚合:
procedure TForm1.Button1Click(Sender: TObject);
begin
FDMemTable1.Aggregates.Clear;
with FDMemTable1.Aggregates.Add do
begin
Name := 'SUM';
Expression := 'sum(iif(ID like ''A%'', value, 0))';
Active := True;
end;
FDMemTable1.AggregatesActive := True;
FDMemTable1.Refresh;
Button1.Caption := VarToStr(FDMemTable1.Aggregates[0].Value));
end;