Adding a calculated field to a Query at run time

James Barrass picture James Barrass · Mar 26, 2010 · Viewed 21.5k times · Source

I'm getting data using a query in Delphi, and would like to add a calculated field to the query before it runs. The calculated field is using values in code as well as the query so I can't just calculate it in SQL.

I know I can attach an OnCalcFields Event to actually make the calculation, but the problem is after adding the calculated field there are no other fields in the query...

I did some digging and found that all of the field defs are created but the actual fields are only created

if DefaultFields then
    CreateFields

Default Fields is specified

procedure TDataSet.DoInternalOpen;
begin
    FDefaultFields := FieldCount = 0;
    ...
end;

Which would indicate that if you add fields you only get the fields you added.

I would like all the fields in the query AS WELL AS the ones I Add.

Is this possible or do I have to add all the fields I'm using as well?

Answer

Francesca picture Francesca · Mar 26, 2010

Nothing prevents you from creating all the fields first in your code,
then add your calculated fields.

You can either use a "hacked type" to use the protected CreateFields:

type
  THackQuery = class(TADOQuery)
  end;
[...]
  MyQuery.FieldDefs.Update;
  THackQuery(MyQuery).CreateFields;

or borrowing some code from CreateFields:

  MyQuery.FieldDefs.Update;
  // create all defaults fields
  for I := 0 to MyQuery.FieldDefList.Count - 1 do
    with MyQuery.FieldDefList[I] do
      if (DataType <> ftUnknown) and not (DataType in ObjectFieldTypes) and
        not ((faHiddenCol in Attributes) and not MyQuery.FIeldDefs.HiddenFields) then
        CreateField(Self, nil, MyQuery.FieldDefList.Strings[I]);

then create your calculated fields:

  MyQueryMyField := TStringField.Create(MyQuery);
  with MyQueryMyField do
  begin
    Name := 'MyQueryMyField';
    FieldKind := fkCalculated;
    FieldName := 'MyField';
    Size := 10;
    DataSet := MyQuery;
  end;