2010-03-26 97 views
7

我在Delphi中使用查询来获取数据,并且希望在查询运行之前将计算字段添加到查询中。计算的字段使用代码中的值以及查询,所以我不能只用SQL来计算它。在运行时向查询添加计算字段

我知道我可以将一个OnCalcFields事件实际上使计算,但问题是将计算出来的后场有查询中没有任何其他领域......

我做了一些挖掘和发现所有创建领域DEFS但实际字段只创建​​

if DefaultFields then 
    CreateFields 

默认字段指定

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

WHI ch会表明如果你添加字段,你只能得到你添加的字段。

我想查询中的所有字段以及我添加的字段。

这是可能的还是我必须添加我使用的所有字段?

+0

我不明白你为什么不能从您的SQL代码使用的值....我建立定期动态SQL语句从SQL代码是使用价值.... – Leslie 2010-03-26 16:58:01

+0

看我的答案为自德尔福柏林 – 2017-09-27 08:25:12

+0

以来做到这一点的一种新方式您是否尝试了PREPARE查询?它可能已经创建了fielddefs(不是字段对象) – 2017-09-27 09:45:00

回答

-1

的Delphi现在能够自动生成的字段和计算字段结合的选项:Data.DB.TFieldOptions.AutoCreateModeTFieldsAutoCreationMode类型的枚举。这样您可以在运行时添加计算的字段。弗朗索瓦在他的回答中写道如何在运行时添加一个字段。 TFieldsAutoCreationMode的

不同的模式:

  • acExclusive

    当不存在持久性字段的话,那么将创建的自动字段。这是默认模式。

  • acCombineComputed

    当数据集不具有持久字段或仅存在计算持久字段被创建的自动字段。这是在设计时创建持久计算字段并让数据集创建自动数据字段的一种便捷方式。当没有持久字段

  • acCombineAlways

    的数据库字段的自动字段将被创建。

+0

它看起来像允许组合设计时间计算字段和运行时数据字段。你是否在答案中测试/成功了你所声称的东西? – 2017-10-01 14:28:39

+0

这不是数学作业,你必须'证明'一切。在另一个回答中描述了在运行时创建字段的代码。 – 2017-10-02 08:35:12

+0

那么,文档没有说明你声称的内容。 – 2017-10-02 13:31:03

3

您需要添加除计算字段以外的所有字段。

一旦添加了一个字段,就必须在数据集中添加所需的所有字段。

德尔福调用这个持久字段与动态字段。所有字段都是永久性的或动态的。不幸的是,你不能混合两者。

另一件事要注意,从文档

持久字段部件列表被 存储在您的应用程序,即使 数据库中的数据集基本的结构是 改变不 变化。

所以,要小心,如果您稍后向表中添加其他字段,则需要将新字段添加到组件。与删除字段相同的东西。

如果你真的不想持久性字段,还有另一种解决方案。在任何应显示计算字段的网格或控件上,可以自定义绘制它。例如,许多网格控件都有一个OnCustomDraw事件。你可以在那里做你的计算。

10

没有什么能阻止你在你的代码中首先创建所有的字段,
然后添加你的计算字段。

您可以使用 “黑客式” 使用受保护的CreateFields:

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

或借用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]); 

然后创建您的计算字段:

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

如果您继承了TQuery或其他TDataset类型的子类,则不需要“破解”来访问受保护的字段。 (a)在代码中添加一个计算字段,以及(b)整个事件在代码中,例如您正在编写完整的代码中的自定义查询或组件。 – 2012-01-09 14:54:30

1

如果您已经知道您在runti计算字段名称我可以使用类似的东西。

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;