2010-03-26 27 views
7

Estoy obteniendo datos usando una consulta en Delphi, y me gustaría agregar un campo calculado a la consulta antes de que se ejecute. El campo calculado usa valores en el código así como en la consulta, por lo que no puedo calcularlo en SQL.Agregar un campo calculado a una consulta en tiempo de ejecución

Sé que puedo adjuntar un OnCalcFields Evento para hacer realidad el cálculo, pero el problema es después de añadir el campo calculado no hay otros campos en la consulta ...

hice algo de investigación y encontró que todos de los defs campo se crean pero los campos reales sólo se crean

se especifica
if DefaultFields then 
    CreateFields 

campos predeterminados

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

Whi ch indicaría que si agrega campos, solo obtendrá los campos que agregó.

Me gustaría tener todos los campos de la consulta ASÍ COMO los que agrego.

¿Es esto posible o tengo que agregar todos los campos que estoy usando también?

+0

No entiendo por qué no puede utilizar los valores del código en su SQL .... construyo sentencias SQL dinámicas con regularidad que los valores de uso del código en el SQL .... ver – Leslie

+0

mi respuesta para una nueva forma de hacerlo desde Delphi Berlín –

+0

¿intentó INTENTAR la consulta? Podría haber creado definiciones de campo (aunque no objetos de campo) –

Respuesta

-1

Delphi tiene ahora la opción de combinar campos generados automáticas y campos calculados: Data.DB.TFieldOptions.AutoCreateMode una enumeración de tipo TFieldsAutoCreationMode. De esta forma, puede agregar sus campos calculados en tiempo de ejecución. Francois escribió en su respuesta cómo agregar un campo en tiempo de ejecución.

Diferentes modos de TFieldsAutoCreationMode:

  • acExclusive

    Cuando no hay campos persistentes en absoluto, entonces se crean campos automáticos. Este es el modo por defecto.

  • acCombineComputed

    Los campos automáticos se crean cuando el conjunto de datos no tiene campos persistentes o hay campos persistentes única calculados. Esta es una forma conveniente de crear los campos calculados persistentes en el momento del diseño y permite que el conjunto de datos cree campos de datos automáticos.

  • acCombineAlways

    campos automáticos para los campos de la base se crean cuando no hay campos persistentes.

+0

Parece que esto permite combinar campos calculados de tiempo de diseño y campos de datos de tiempo de ejecución. ¿Has probado/tenido éxito lo que reclamas en la respuesta? –

+0

Esto no es tarea de matemáticas donde tienes que 'probar' todo. El código para crear un campo en tiempo de ejecución se describe en otra respuesta –

+0

Bueno, la documentación no dice lo que usted reclama. –

3

Debe agregar todos los campos además de su campo calculado.

Una vez que agrega un campo, debe agregar todos los campos que desea en el conjunto de datos.

Delphi llama a esto campos persistentes frente a campos dinámicos. Todos los campos son persistentes o dinámicos. Desafortunadamente, no puedes tener una mezcla de ambos.

Otra cosa a destacar, a partir de la documentación es

campos persistentes listas de componentes se almacenados en su aplicación, y no lo hacen cambio incluso si la estructura de una base de datos subyace un conjunto de datos es cambiado.

Por lo tanto, tenga cuidado, si luego agrega campos adicionales a una tabla, deberá agregar los nuevos campos al componente. Lo mismo con la eliminación de campos.

Si realmente no desea campos persistentes, hay otra solución. En cualquier cuadrícula o control que debe mostrar el campo calculado, puede dibujarlo a medida. Por ejemplo, muchos controles de cuadrícula tienen un evento OnCustomDraw. Puedes hacer tu cálculo allí.

10

Nada le impide crear todos los campos primero en su código,
luego agregue los campos calculados.

También se puede usar un "tipo hackeado" para usar los CreateFields protegidas:

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

o prestatarios algún código de 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]); 

luego crear sus campos calculados:

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

En el caso en que esté subclasificando un TQuery u otro tipo de TDataset, no necesita "piratear" para acceder a los campos protegidos. Esta respuesta es la correcta cuando está (a) agregando un campo calculado en el código, y (b) todo está en el código tal como está escribiendo una consulta personalizada o un componente completo en el código. –

1

Si conoce los nombres de los campos para calcular en runti yo, puedes usar algo así.

var 
initing:boolean; 

procedure TSampleForm.dsSampleAfterOpen(
    DataSet: TDataSet); 
var 
i:integer; 
dmp:tfield; 
begin 
if not initing then 
try 
    initing:=true; 
    dataset.active:=false; 
    dataset.FieldDefs.Update; 
    for i:=0 to dataset.FieldDefs.Count-1 do 
    begin 
    dmp:=DataSet.FieldDefs.Items[i].FieldClass.Create(self); 
    dmp.FieldName:=DataSet.FieldDefs.Items[i].DisplayName; 
    dmp.DataSet:=dataset; 
    if (dmp.fieldname='txtState') or (dmp.FieldName='txtOldState') then 
    begin 
    dmp.Calculated:=true; 
    dmp.DisplayWidth:=255; 
    dmp.size:=255; 
    end; 
    end; 
    dataset.active:=true; 
finally 
    initing:=false; 
end; 
end; 

procedure TSampleForm.dsSampleAfterClose(
    DataSet: TDataSet); 
var 
i:integer; 
dmp:TField; 
begin 
if not initing then 
begin 
for i:=DataSet.FieldCount-1 downto 0 do 
begin 
    dmp:=pointer(DataSet.Fields.Fields[i]); 
    DataSet.Fields.Fields[i].DataSet:=nil; 
    freeandnil(dmp); 
end; 
DataSet.FieldDefs.Clear; 
end; 
end; 

procedure TSampleForm.dsSampleCalcFields(
    DataSet: TDataSet); 
var 
tmpdurum,tmpOldDurum:integer; 
begin 
    if not initing then 
    begin 
     tmpDurum := dataset.FieldByName('state').AsInteger; 
     tmpOldDurum:= dataset.FieldByName('oldstate').AsInteger; 
     dataset.FieldByName('txtState').AsString := State2Text(tmpDurum); 
     dataset.FieldByName('txtOldState').AsString := State2Text(tmpOldDurum); 
    end; 
end; 

procedure TSampleForm.btnOpenClick(Sender: TObject); 
begin 
if dsSample.Active then 
    dsSample.Close; 
dsSample.SQL.text:='select id,state,oldstate,"" as txtState,"" as txtOldState from states where active=1'; 
dsSample.Open; 
end; 
Cuestiones relacionadas