请问如何在Query中filter calculated field? |
答題得分者是:Chance36
|
ebx
一般會員 發表:1 回覆:20 積分:9 註冊:2003-10-09 發送簡訊給我 |
我試了以下兩種方法,均行不通,望各位賜教 1.
Filter := 'ABS = 1';
會出現 Field 'ABS' cannot be used in a filter expression. 2.
qryStaffOnFilterRecord:
Accept := qryStaff.FieldByName('ABS').AsFloat >= 1; Main Program:
qryStaff.Filtered := TRUE; 這時會出現qryStaff完全沒有資料
但是如果改成Accept := qryStaff.FieldByName('ABS').AsFloat > 0;
則會出現資料(不對的) 經檢查,發現是 onFilterRecord 的執行次序高於 onCalculateFields
也就是說,當執行到Accept := qryStaff.FieldByName('ABS').AsFloat
這行時,ABS 還未取得正確的值,這也解釋了為什麼改成
Accept := qryStaff.FieldByName('ABS').AsFloat > 0;
則會出現資料(因為ABS 這時的值是亂七八糟的且大於0) 我的環境是 WinXP Home SP1, Delphi6, Foxpro table.
|
Chance36
版主 發表:31 回覆:1033 積分:792 註冊:2002-12-31 發送簡訊給我 |
ebx 你好
即然發現是 onFilterRecord 的執行次序高於 onCalculateFields, 那麼可以用第二種方法,自行觸發onCalcFields事件 2. qryStaffOnFilterRecord: qryStaff.OnCalcFields(Sender); // 自行觸發OnCalcFields Accept := qryStaff.FieldByName('ABS').AsFloat >= 1; Main Program: qryStaff.Filtered := TRUE; |
ebx
一般會員 發表:1 回覆:20 積分:9 註冊:2003-10-09 發送簡訊給我 |
|
Chance36
版主 發表:31 回覆:1033 積分:792 註冊:2002-12-31 發送簡訊給我 |
|
ko
資深會員 發表:28 回覆:785 積分:444 註冊:2002-08-14 發送簡訊給我 |
|
ebx
一般會員 發表:1 回覆:20 積分:9 註冊:2003-10-09 發送簡訊給我 |
Chance36 你好, 1. qryStaff 與 tblDaily 關係是Master-Detail
2. qryStaffABS 的值是即時從tblDaily計算得來的
3. 麻煩你了! < class="code"> procedure TForm1.SetDailyRange;
begin
with tblDaily do
begin
CancelRange;
SetRangeStart;
FieldByName('Emp_Code').AsString := qryStaffEmp_Code.Value;
FieldByName('Date').AsDateTime := EncodeDate(2004, 2, 1);
SetRangeEnd;
FieldByName('Emp_Code').AsString := qryStaffEmp_Code.Value;
FieldByName('Date').AsDateTime := EncodeDate(2004, 2, 24);
ApplyRange;
end;
end; procedure TForm1.tblDailyFilterRecord(DataSet: TDataSet;
var Accept: Boolean);
begin
Accept := tblDailyREASON.Value = 'ABS';
end; procedure TForm1.qryStaffCalcFields(DataSet: TDataSet);
begin
if tblDailyEMP_CODE.Value <> qryStaffEMP_CODE.Value then
SetDailyRange; tblDaily.First;
while not tblDaily.Eof do
begin
if tblDailyREASON.Value = 'ABS' then
qryStaffABS.Value := qryStaffABS.Value 1;
tblDaily.Next;
end; // ShowMessage('OnCalcFields ' qryStaffEmp_Code.Value ' ' FloatToStr(qryStaffABS.Value));
end; procedure TForm1.qryStaffFilterRecord(DataSet: TDataSet;
var Accept: Boolean);
begin
qryStaffCalcFields(DataSet);
// ShowMessage('OnFilterRecord ' qryStaffEmp_Code.Value ' ' FloatToStr(qryStaffABS.Value));
Accept := qryStaffABS.Value > 0;
end; procedure TForm1.qryStaffAfterScroll(DataSet: TDataSet);
begin
// if tblDailyEMP_CODE.Value <> qryStaffEMP_CODE.Value then
// SetDailyRange;
end; procedure TForm1.Button1Click(Sender: TObject);
begin
// qryStaff.AutoCalcFields := FALSE;
qryStaff.Filtered := TRUE;
end;
|
ebx
一般會員 發表:1 回覆:20 積分:9 註冊:2003-10-09 發送簡訊給我 |
|
Chance36
版主 發表:31 回覆:1033 積分:792 註冊:2002-12-31 發送簡訊給我 |
procedure TForm1.qryStaffCalcFields(DataSet: TDataSet); begin if tblDailyEMP_CODE.Value <> qryStaffEMP_CODE.Value then SetDailyRange; tblDaily.First; qryStaffABS.Value := 0; // 要先歸零 while not tblDaily.Eof do begin if tblDailyREASON.Value = 'ABS' then qryStaffABS.Value := qryStaffABS.Value 1; tblDaily.Next; end; // ShowMessage('OnCalcFields ' qryStaffEmp_Code.Value ' ' FloatToStr(qryStaffABS.Value)); end; procedure TForm1.qryStaffFilterRecord(DataSet: TDataSet; var Accept: Boolean); begin qryStaffCalcFields(DataSet); // ShowMessage('OnFilterRecord ' qryStaffEmp_Code.Value ' ' FloatToStr(qryStaffABS.Value)); Accept := qryStaffABS.Value > 0; end; procedure TForm1.Button1Click(Sender: TObject); begin // qryStaff.AutoCalcFields := FALSE; qryStaff.Filtered := TRUE; end; |
ebx
一般會員 發表:1 回覆:20 積分:9 註冊:2003-10-09 發送簡訊給我 |
不行
引言:procedure TForm1.qryStaffCalcFields(DataSet: TDataSet); begin if tblDailyEMP_CODE.Value <> qryStaffEMP_CODE.Value then SetDailyRange; tblDaily.First; qryStaffABS.Value := 0; // 要先歸零 while not tblDaily.Eof do begin if tblDailyREASON.Value = 'ABS' then qryStaffABS.Value := qryStaffABS.Value 1; tblDaily.Next; end; // ShowMessage('OnCalcFields ' qryStaffEmp_Code.Value ' ' FloatToStr(qryStaffABS.Value)); end; procedure TForm1.qryStaffFilterRecord(DataSet: TDataSet; var Accept: Boolean); begin qryStaffCalcFields(DataSet); // ShowMessage('OnFilterRecord ' qryStaffEmp_Code.Value ' ' FloatToStr(qryStaffABS.Value)); Accept := qryStaffABS.Value > 0; end; procedure TForm1.Button1Click(Sender: TObject); begin // qryStaff.AutoCalcFields := FALSE; qryStaff.Filtered := TRUE; end; |
Chance36
版主 發表:31 回覆:1033 積分:792 註冊:2002-12-31 發送簡訊給我 |
再試試以下程式 //SetDailyRange移動AfterScroll事件中 procedure TForm1.qryStaffAfterScroll(DataSet: TDataSet); begin // if tblDailyEMP_CODE.Value <> qryStaffEMP_CODE.Value then SetDailyRange; // <----- 放到AfterScroll事件中 End; procedure TForm1.qryStaffCalcFields(DataSet: TDataSet); Var Cnt : Integer ; begin { // 移到AfterScroll事件中 if tblDailyEMP_CODE.Value <> qryStaffEMP_CODE.Value then SetDailyRange; } tblDaily.First; Cnt := 0 ; // 要先歸零 while not tblDaily.Eof do begin if tblDailyREASON.Value = 'ABS' then Inc(Cnt); tblDaily.Next; end; qryStaffABS.Value := Cnt; // ShowMessage('OnCalcFields ' qryStaffEmp_Code.Value ' ' FloatToStr(qryStaffABS.Value)); end; procedure TForm1.qryStaffFilterRecord(DataSet: TDataSet; var Accept: Boolean); begin qryStaff.Edit; qryStaffCalcFields(DataSet); qryStaff.Post; // ShowMessage('OnFilterRecord ' qryStaffEmp_Code.Value ' ' FloatToStr(qryStaffABS.Value)); Accept := qryStaffABS.Value > 0; end; procedure TForm1.Button1Click(Sender: TObject); begin // qryStaff.AutoCalcFields := FALSE; qryStaff.Filtered := TRUE; end;PS:一句[不行]會讓人傻眼的,而且也達不到互動討論的效果,對於問題的真象分析更是沒有幫助。 |
ebx
一般會員 發表:1 回覆:20 積分:9 註冊:2003-10-09 發送簡訊給我 |
引言:不好意思,因為「不行」的原因與之前的一樣就是 「很奇怪,自行觸發onCalcFields事件所得到的值是錯的!!」 所以就沒有略加說明。 1. 對於這次的修改,我想你是基於有使用一個TUpdateSQL,以及設定CacheUpdate/ReqeustLive 為TRUE 的情況下測試的吧,要不然會出現'qryStaff: Cannot modify a readonly dataset.' 2. 至於把SetDailyRange 移至AfterScroll, 會導致在完成了整個qryStaff.Filtered := TRUE 的事件後才會觸發一次SetDailyRange,而不是我要的每一筆記錄一次觸發SetDailyRange。 3. 再來是關鍵的地方,(使用一個TUpdateSQL,以及設定CacheUpdate/ReqeustLive 為TRUE 的情況下)再試試以下程式 //SetDailyRange移動AfterScroll事件中 procedure TForm1.qryStaffAfterScroll(DataSet: TDataSet); begin // if tblDailyEMP_CODE.Value <> qryStaffEMP_CODE.Value then SetDailyRange; // <----- 放到AfterScroll事件中 End;..... PS:一句[不行]會讓人傻眼的,而且也達不到互動討論的效果,對於問題的真象分析更是沒有幫助。 procedure TForm1.qryStaffFilterRecord(DataSet: TDataSet; var Accept: Boolean); begin qryStaff.Edit; qryStaffCalcFields(DataSet); qryStaff.Post; // ShowMessage('OnFilterRecord ' qryStaffEmp_Code.Value ' ' FloatToStr(qryStaffABS.Value)); Accept := qryStaffABS.Value > 0; end;有三種情況 1. 不作任何修改,會出現'Record already locked by thi session' > > |
Chance36
版主 發表:31 回覆:1033 積分:792 註冊:2002-12-31 發送簡訊給我 |
1. 對於這次的修改,我想你是基於有使用一個TUpdateSQL,以及設定CacheUpdate/ReqeustLive 為TRUE 的情況下測試的吧,要不然會出現'qryStaff: Cannot modify a readonly dataset.' 2. 至於把SetDailyRange 移至AfterScroll, 會導致在完成了整個qryStaff.Filtered := TRUE 的事件後才會觸發一次SetDailyRange,而不是我要的每一筆記錄一次觸發SetDailyRange。
[/quote]
ebx 你好 我想我大概了解狀況了,
1.qryStaff是個唯讀的資料集,應該是SQL中有關聯或用到Order By等指令。故在OnFilterRecord不能Edit後再Post。
2.OnFilterRecord 好像會停止其他事件的觸發,所以AfterScroll及OnCalcFields事件都沒反應。
因此之故,在OnFilterRecord事件中,凡事都要自已來,且要注意不要動到自身(DataSet)的記錄指標,免得造成循環觸發OnFilterRecord事件。
procedure TForm1.qryStaffFilterRecord(DataSet: TDataSet; var Accept: Boolean); Var ABS : Integer ; begin SetDailyRange; // ABS := 0 ; // 要先歸零 while not tblDaily.Eof do begin if tblDailyREASON.Value = 'ABS' then Inc(ABS ); tblDaily.Next; end; Accept := ABS > 0; //使用變數來判斷 end; procedure TForm1.qryStaffCalcFields(DataSet: TDataSet); Var Cnt : Integer ; begin SetDailyRange; tblDaily.First; Cnt := 0 ; // 要先歸零 while not tblDaily.Eof do begin if tblDailyREASON.Value = 'ABS' then Inc(Cnt); tblDaily.Next; end; qryStaffABS.Value := Cnt; // ShowMessage('OnCalcFields ' qryStaffEmp_Code.Value ' ' FloatToStr(qryStaffABS.Value)); end; |
peipei36
一般會員 發表:8 回覆:51 積分:16 註冊:2002-03-13 發送簡訊給我 |
看了Chance36版主 的結論才大概了解這是在做什麼事..
您看這樣是不是您要的..
但我沒用 Range..(用了可能也要跑迴圈處理..)
雖然感覺動作是正常了
但還是覺得 CalcFields 拿來這樣用..整個運作怪怪的..
每一個CalcFields做一次detail的filter..
資料量大些時 會不會不好跑..
var cntAbs:integer; procedure TForm1.qryStaffAfterScroll(DataSet: TDataSet); begin SetDailyRange; end; procedure TForm1.SetDailyRange; begin with tblDaily do begin Filter := 'emp_code=''' qryStaff.Fieldbyname('emp_code').AsString ''' and date > ''2004/02/01'' and date < ''2004/02/24'''; Filtered:=true; end; end; procedure TForm1.Button1Click(Sender: TObject); begin tblDaily.Open; qryStaff.Open; end; procedure TForm1.qryStaffCalcFields(DataSet: TDataSet); begin cntAbs:=0; //if tblDaily.State=dsInactive then tblDaily.Open; SetDailyRange; dataset.FieldByName('abs').AsInteger:=cntAbs; end; procedure TForm1.tblDailyFilterRecord(DataSet: TDataSet; var Accept: Boolean); begin if (dataset.FieldByName('reason').AsString='ABS') then inc(cntAbs); end; |
ebx
一般會員 發表:1 回覆:20 積分:9 註冊:2003-10-09 發送簡訊給我 |
|
Mickey
版主 發表:77 回覆:1882 積分:1390 註冊:2002-12-11 發送簡訊給我 |
|
ebx
一般會員 發表:1 回覆:20 積分:9 註冊:2003-10-09 發送簡訊給我 |
本站聲明 |
1. 本論壇為無營利行為之開放平台,所有文章都是由網友自行張貼,如牽涉到法律糾紛一切與本站無關。 2. 假如網友發表之內容涉及侵權,而損及您的利益,請立即通知版主刪除。 3. 請勿批評中華民國元首及政府或批評各政黨,是藍是綠本站無權干涉,但這裡不是政治性論壇! |