2010-03-26 100 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;