Calculated and aggregated fields are dynamic fields that are not physically stored in a database. Their values are calculated on the client side when required.
The following sections outline the process of working with these fields and detail their main characteristics.
The article demonstrates how to use calculated and aggregated fields through practical examples. The examples are based on a test database table named demo.
You can create the test table by running the following script:
CREATE TABLE demo
(
id integer PRIMARY KEY,
name varchar(50),
itemprice money,
itemcount integer,
itemtaxes integer
)
Note: Each sample query processes all records in the demo table.
Calculated fields are designed to perform calculations using any defined calculation logic or formula. These calculations can be carried out through various types of calculated fields.
MyDAC supports the following types of calculated fields:
fkCalculated - A simple calculated field that allows performing calculations using a single function defined in the OnCalcFields event.fkInternalCalc - An advanced calculated field where a calculation is defined by a single default expression or in the OnCalcFields event.fkLookup - A lookup field is used to retrieve values from related tables or datasets. Calculated fields can be defined either at design time through the user interface or at runtime using code. The following sections provide practical examples of how to work with the fields programmatically.
This code example demonstrates how to define and apply a function to a calculated field using fkCalculated. When you run the code, the UName field displays the uppercase value of the Name field followed by the lowercase value of the Trim field.
Note: When using fkCalculated, you can assign custom procedure names to your calculations.
// Triggered when Button1 is clicked
procedure TForm1.Button1Click(Sender: TObject);
var
oField: TField;
i: Integer;
begin
// Refresh the dataset structure before making changes
MyQuery1.Close;
MyQuery1.FieldDefs.Updated := False;
MyQuery1.FieldDefs.Update;
// Create persistent fields from field definitions
for i := 0 to MyQuery1.FieldDefs.Count - 1 do
MyQuery1.FieldDefs[i].CreateField(Self);
// Create a new calculated field with specific parameters
oField := TStringField.Create(MyQuery1);
oField.Size := 50;
oField.FieldName := 'UName';
oField.FieldKind := fkCalculated;
oField.DataSet := MyQuery1;
// Assign the OnCalcFields event handler for calculated fields
MyQuery1.OnCalcFields := MyCalcFields;
// Open the query to fetch data and trigger the calculation
MyQuery1.Open;
end;
procedure TForm1.MyCalcFields(DataSet: TDataSet);
begin
// Convert the Name field value to uppercase and display the result in the UName field.
DataSet.FieldByName('UName').AsString := UpperCase(DataSet.FieldByName('Name').AsString) + LowerCase(DataSet.FieldByName('Trim').AsString);
end;
This code example illustrates how to define and apply a single expression to a calculated field using fkInternalCalc. When you run the code, the UName field displays the uppercase value of the Name field.
// Triggered when Button2 is clicked
procedure TForm1.Button2Click(Sender: TObject);
var
oField: TField;
i: Integer;
begin
// Refresh the dataset structure before making changes
MyQuery2.Close;
MyQuery2.FieldDefs.Updated := False;
MyQuery2.FieldDefs.Update;
// Create persistent fields from field definitions
for i := 0 to MyQuery2.FieldDefs.Count - 1 do
MyQuery2.FieldDefs[i].CreateField(Self);
// Create a new calculated field with specific parameters
oField := TStringField.Create(MyQuery2);
oField.Size := 50;
oField.FieldName := 'UName';
oField.FieldKind := fkInternalCalc;
oField.DefaultExpression := 'UPPER(Name)';
oField.DataSet := MyQuery2;
// Open the dataset to make fields available for use
MyQuery2.Open;
end;
This code example illustrates how to define and apply a dynamic lookup field to a dataset. When you run the code, the Lookup field displays values retrieved from the ID fields in the main (MyQuery4) and lookup (MyQuery5) datasets.
// Triggered when Button3 is clicked
procedure TForm1.Button3Click(Sender: TObject);
var
LookupField: TStringField;
i: integer;
begin
// Refresh the dataset structure before making changes
MyQuery4.Close;
MyQuery4.FieldDefs.Updated := False;
MyQuery4.FieldDefs.Update;
//Create fields for MyQuery4
for i := 0 to MyQuery4.FieldDefs.Count - 1 do
MyQuery4.FieldDefs[i].CreateField(Self);
// Create a new lookup field with specific parameters
LookupField := TStringField.Create(MyQuery4);
LookupField.FieldName := 'Lookup';
LookupField.FieldKind := fkLookup;
//Define a secondary dataset used for lookup values
LookupField.LookupDataSet := MyQuery5;
//Define a key field in the main dataset (MyQuery4) that links to the lookup dataset
LookupField.KeyFields := 'ID';
//Define the corresponding key field in the lookup dataset (MyQuery5)
LookupField.LookupKeyFields := 'ID';
//Specify a field in the lookup dataset to display as the lookup result
LookupField.LookupResultField := 'Name';
LookupField.DataSet := MyQuery4;
LookupField.Index := MyQuery4.FieldDefs.Count;
MyQuery4.Open;
end;
Aggregated fields allow you to perform calculations by using SQL aggregate functions such as MIN(), MAX(), SUM(), COUNT(), and AVG().
This example shows how to define and apply an aggregate function to an aggregated field. When you run the code, the Total field displays the total value of items by summing the result of the formula (itemprice + itemtaxes) * itemcount across all records.
// Triggered when Button4 is clicked
procedure TForm1.Button4Click(Sender: TObject);
var
oField: TAggregateField;
i: Integer;
begin
// Refresh the dataset structure before making changes
MyQuery3.Close;
MyQuery3.FieldDefs.Updated := False;
MyQuery3.FieldDefs.Update;
// Create persistent fields from field definitions
for i := 0 to MyQuery3.FieldDefs.Count - 1 do
MyQuery3.FieldDefs[i].CreateField(Self);
// Create a new aggregated field with specific parameters
oField := TAggregateField.Create(MyQuery3);
oField.Active := True;
oField.FieldName := 'Total';
// Define the aggregated expression
oField.Expression := 'SUM((itemprice + itemtaxes) * itemcount)';
oField.DataSet := MyQuery3;
// Enable aggregated calculations and associate the aggregated field with the dataset
MyQuery3.AggregatesActive := True;
MyQuery3.Open;
// Display the calculated total value in a message box
ShowMessage(FloatToStr(MyQuery3.FieldByName('Total').Value));
end;