大量資料存取效能不高之解決方法? |
答題得分者是:Justmade
|
challenge
一般會員 發表:14 回覆:41 積分:11 註冊:2002-10-08 發送簡訊給我 |
各位前輩您好…因我要做統計計算…需處理上萬筆資料…本來的做法是採用
邊算邊insert進mysql資料庫…結果只處理800多筆資料就run了三分鐘…
現在的想法是想將mysql會用到的資料table先select出來並存成陣列…再從陣
列insert進由paradox所產生的table…也就是想在local端的資料庫執行完後再
存回mysql…不曉得這樣的想法會不會比較快?或是須要改進… 上面的方式我正在試…只是我要從陣列insert進paradox產生的table時…卻發現型態不符的情況…可paradox資料表裡所提供的型態有點不同…我取以最類似的
型態來使用…insert程式如下:
for a:= 0 to d-1 do
begin
with query2 do
begin
close;
sql.clear;
sql.add('INSERT INTO ALL_CLASS(CRS_ID,QUES_ID,TEA_ID,PEOPLE)VALUES(:Vcrs_id,:Vques_id,:Vtea_id,:Vpeople)');
Prepare;
ParamByName('Vcrs_id').AsString:= all[a][0];
ParamByName('Vques_id').AsString:= all[a][1];
ParamByName('Vtea_id').AsString:= all[a][2];
ParamByName('Vpeople').AsString:= all[a][3];
ExecSQL;
end;//withquery4
end;
謝謝…^^
|
timhuang
尊榮會員 發表:78 回覆:1815 積分:1608 註冊:2002-07-15 發送簡訊給我 |
Hi, 先針對你的第一個問題, 統計計算的資料是否有相依性的問題.
若是沒有的話, 即使速度慢, 可以分次計算應該是沒有問題的, 但不
知速度慢的原因為何, 若是卡在 insert 上面的話, 即使你在 client
端先作好再 insert 的話, 應該也不會改善的. 要看發生速度慢的原
因為何才能決定這樣的作法是否合適.
第二個 paradox 產生型態不符的問題, 可否列出錯誤訊息, 另外你的
程式碼的部分沒有什麼問題, 是否 all 陣列的型態有問題, 或是 table
的欄位型態不是字串呢? 可否列出較完整的說明, 讓大家幫你看看.
|
challenge
一般會員 發表:14 回覆:41 積分:11 註冊:2002-10-08 發送簡訊給我 |
引言: Hi, 先針對你的第一個問題, 統計計算的資料是否有相依性的問題. 若是沒有的話, 即使速度慢, 可以分次計算應該是沒有問題的, 但不 知速度慢的原因為何, 若是卡在 insert 上面的話, 即使你在 client 端先作好再 insert 的話, 應該也不會改善的. 要看發生速度慢的原 因為何才能決定這樣的作法是否合適. 第二個 paradox 產生型態不符的問題, 可否列出錯誤訊息, 另外你的 程式碼的部分沒有什麼問題, 是否 all 陣列的型態有問題, 或是 table 的欄位型態不是字串呢? 可否列出較完整的說明, 讓大家幫你看看. 非常感謝有你的講解^^…基本上統計結果產生前的幾個table間的資料都有 相依性,因資料要開始計算前會有一大串…尤其是選擇題填答結果的那個table…一個人填完一份問卷就會有十幾筆記錄…也不太清楚如何做分次計 算…我覺得最花時間的是我以下的程式…我用了三個迴圈、一個陣列,每 完成一筆就會insert進去…而且在完成一筆前還要跟mysql做好幾次的比對, 我想…這樣會不會很沒效率…才導致我才26個人填問卷就run了三分鐘… 真怕三千人填的話…系統就掛了…^^" //產生所有問卷 課程 教師組合 with query1 do begin close; sql.Clear; sql.Add('select distinct QUES_ID,CRS_ID,TEA_ID from EACH_QUES_QS_COUNT'); Prepare; open end; //將所有問卷 課程 教師放入ary[]; x:=query1.RecordCount; setLength(ary, x); // 設定動態陣列 i:=0; with query1 do begin first; while not eof do begin ary[i][0]:= query1.Fields[0].AsString; ary[i][1]:= query1.Fields[1].AsString; ary[i][2]:= query1.Fields[2].AsString; next; i:=i 1; end; //showmessage( inttostr(i)); //測試用 end; //迴圈開始 //第一層迴圈由ary陣列裡面的值(所有問卷 課程 教師)做比對 for a:= 0 to x-1 do begin //求問卷題數 with query2 do begin close; sql.Clear; sql.Add('select QL_NO from QUESTION_QL where QL_TYPE=''0'' and QUES_ID=''' ary[a][0] ''''); Prepare; open end;//with query2 y:=query2.RecordCount; //showmessage(inttostr(y)); //測試用 //第二層迴圈經由第一層迴圈而得知問卷題數 for b:=1 to y do begin //第三層迴圈開始做選項比對,也就是第一份問卷的第一題的第一個選項有 //幾個人填答,在此會有完整結果 for c:= 1 to 5 do begin if c=1 then begin with query3 do begin close; sql.Clear; sql.Add('select TOTAL from EACH_QUES_QS_COUNT where QUES_ID=''' ary[a][0] ''' and CRS_ID=''' ary[a][1] ''' and TEA_ID=''' ary[a][2] ''' and QS_NO=''' inttostr(b) ''' and QS_SEL_ANS=''' inttostr(c) ''''); Prepare; open end;//with query3 if query3.Fields[0].AsString='' then begin c1:=0; end else begin c1:=strtoint(query3.Fields[0].AsString); end; //showmessage(inttostr(c1)); end;//ifc=1 if c=2 then begin with query3 do begin close; sql.Clear; sql.Add('select TOTAL from EACH_QUES_QS_COUNT where QUES_ID=''' ary[a][0] ''' and CRS_ID=''' ary[a][1] ''' and TEA_ID=''' ary[a][2] ''' and QS_NO=''' inttostr(b) ''' and QS_SEL_ANS=''' inttostr(c) ''''); Prepare; open end;//with query3 if query3.Fields[0].AsString='' then begin c2:=0; end else begin c2:=strtoint(query3.Fields[0].AsString); end; //showmessage(inttostr(c2)); end;//ifc=2 if c=3 then begin with query3 do begin close; sql.Clear; sql.Add('select TOTAL from EACH_QUES_QS_COUNT where QUES_ID=''' ary[a][0] ''' and CRS_ID=''' ary[a][1] ''' and TEA_ID=''' ary[a][2] ''' and QS_NO=''' inttostr(b) ''' and QS_SEL_ANS=''' inttostr(c) ''''); Prepare; open end;//with query3 if query3.Fields[0].AsString='' then begin c3:=0; end else begin c3:=strtoint(query3.Fields[0].AsString); end; //showmessage(inttostr(c3)); end;//ifc=3 if c=4 then begin with query3 do begin close; sql.Clear; sql.Add('select TOTAL from EACH_QUES_QS_COUNT where QUES_ID=''' ary[a][0] ''' and CRS_ID=''' ary[a][1] ''' and TEA_ID=''' ary[a][2] ''' and QS_NO=''' inttostr(b) ''' and QS_SEL_ANS=''' inttostr(c) ''''); Prepare; open end;//with query3 if query3.Fields[0].AsString='' then begin c4:=0; end else begin c4:=strtoint(query3.Fields[0].AsString); end; //showmessage(inttostr(c4)); end;//ifc=4 if c=5 then begin with query3 do begin close; sql.Clear; sql.Add('select TOTAL from EACH_QUES_QS_COUNT where QUES_ID=''' ary[a][0] ''' and CRS_ID=''' ary[a][1] ''' and TEA_ID=''' ary[a][2] ''' and QS_NO=''' inttostr(b) ''' and QS_SEL_ANS=''' inttostr(c) ''''); Prepare; open end;//with query3 if query3.Fields[0].AsString='' then begin c5:=0; end else begin c5:=strtoint(query3.Fields[0].AsString); end; //showmessage(inttostr(c5)); end;//ifc=5 end;//c //算每一題的加權平均 r:=((5*c1) (4*c2) (3*c3) (2*c4) (1*c5))/(c1 c2 c3 c4 c5); //開始insert資料到課程整體問卷統計結果,也就是完整得到一筆資料後做insert with query4 do begin close; sql.clear; sql.add('INSERT INTO QUES_CRS_STA (CRS_ID,TEA_ID,QUES_ID,QS_NO,RESULT,QS_SUM1,QS_SUM2,QS_SUM3,QS_SUM4,QS_SUM5)VALUES(:Vcrs_id,:Vtea_id,:Vques_id,:Vqs_no,:Vresult,:Vqs_sum1,:Vqs_sum2,:Vqs_sum3,:Vqs_sum4,:Vqs_sum5)'); Prepare; ParamByName('Vcrs_id').AsString:= ary[a][1]; ParamByName('Vtea_id').AsString:= ary[a][2]; ParamByName('Vques_id').AsString:= ary[a][0]; ParamByName('Vqs_no').Value:= b; ParamByName('Vresult').Value:= r; ParamByName('Vqs_sum1').Value:= c1; ParamByName('Vqs_sum2').Value:= c2; ParamByName('Vqs_sum3').Value:= c3; ParamByName('Vqs_sum4').Value:= c4; ParamByName('Vqs_sum5').Value:= c5; ExecSQL; end;//withquery4 end;//b end;//a end; |
Justmade
版主 發表:94 回覆:1934 積分:2030 註冊:2003-03-12 發送簡訊給我 |
我沒時間完全的看你的程式,但大致上有些建議給你可增加速度,簡單來說,你的程式執行慢主要是你處理 Queryx.sql 的手法而非 insert 執行的慢。即使你用 paradox table 亦不會有幫助的,可能反而變得更慢。 慢的主要原因 : 1. Prepare : Prepare 會耗用資源和時間,當一個Query只執行一次時,Prepare只會比不Prepare慢。但若一句SQL Statment會被重覆執行多次,則每次執行節省的時間,會使Prepare變得值得。可是你每次都執行一次便Clear了 SQL 重新加入,Prepare 又要重新耗用資源和時間,結果只會比不 Prepare 慢。而且,你好像沒用 UnPrepare 來釋放 Prepare 佔用了的資源,處理三千份問卷可能真的會令系統。 class="code">
procedure CalculateStat;
var
c : Array[1..5] of integer
sql : string;
begin
sql := 'INSERT INTO QUES_CRS_STA (QUES_ID,CRS_ID,TEA_ID,QS_NO,RESULT,'
'QS_SUM1,QS_SUM2,QS_SUM3,QS_SUM4,QS_SUM5) VALUES '
Query1.SQL.Text := "select QUES_ID,CRS_ID,TEA_ID,QS_NO,QS_SEL_AS,TOTAL '
'from EACH_QUES_QS_COUNT order by QUES_ID,CRS_ID,TEA_ID,QS_NO,QS_SEL_AS";
Query1.Active := true;
While not Query1.eof do
begin
c[Query1.FieldByName('QS_SEL_AS').Value] := Query1.FieldByName('TOTAL').Value;
if Query1.FieldByName('QS_SEL_AS').Value = 5 then // 該題完結,計算加權及加入一筆資料到 INSERT SQL
begin
r:=((5*c[1]) (4*c[2]) (3*c[3]) (2*c[4]) (1*c[5]))/(c[1] c[2] c[3] c[4] c[5]);
sql := sql '(' Query1.Fields[0].AsString ',' Query1.Fields[1].AsString ','
Query1.Fields[2].AsString ',' Query1.Fields[3].AsString ',' StrToInt(r)
',' StrToInt(C[1]) ',' StrToInt(C[2]) ',' StrToInt(C[3]) ','
StrToInt(C[4]) ',' StrToInt(C[5]) '),'
end // if
Query1.Next;
end;// while
sql := Copy(SQL,1,Length(SQL) - 1); // 除掉最後的 ,
Query1.Active := false;
Query1.SQL.Text := SQL;
Query1.ExecSQL; // 一次過將所有結果 insert
end;
我的做法是這樣的
1. select 時直接將所有相關欄位排列整齊,順著每問卷每題每答案排好
2. 一筆筆資料處理將每答案的 TOTAL 存入 c 陣列,完成一題後計算該題的加權並將該題的資料加入 Update sql 中
3. 所有題目完成後一次過 insert 所有資料到 database 這樣做只需一次 select 及一次 update,應會快很多,試試罷。 若我了解錯了你要做的請告知。 [修改: code 太長改短,sql := copy(...) 錯了更正] 發表人 - Justmade 於 2003/03/17 10:22:27
|
Mickey
版主 發表:77 回覆:1882 積分:1390 註冊:2002-12-11 發送簡訊給我 |
|
Justmade
版主 發表:94 回覆:1934 積分:2030 註冊:2003-03-12 發送簡訊給我 |
引言: 1. 運用 Store Procedure (MySQL 4.x 不知有沒有).沒有耶 <>< face="Verdana, Arial, Helvetica">引言: 2. 彙算用的大量原始資料, 避免 open 到前端來. ( 多運用 SQL : sum / avg 等 function, 讓 DB Server 先做初步的收整 ) 我本來都想建議他用 count 但後看看他的數量庫已將相同的合案count了放在Total 欄,只是要將同一題的各答案總數放在一起並計算加權,不知有沒看錯。 |
timhuang
尊榮會員 發表:78 回覆:1815 積分:1608 註冊:2002-07-15 發送簡訊給我 |
|
challenge
一般會員 發表:14 回覆:41 積分:11 註冊:2002-10-08 發送簡訊給我 |
謝謝你幫我將程式做了詳細的分析…難怪我的程式跑那麼慢…^^"
我大致上將我的程式更改如下…只是為何會出現「List Index out of bounds(3)」的錯誤訊息…還有…這一行「sql := Copy(SQL,1,Length(SQL) - 1); // 除掉最後的,」,主要的作用為何? //迴圈開始
//第一層迴圈由ary陣列裡面的值(所有問卷+課程+教師)做比對
for a:= 0 to x-1 do
begin
//求問卷題數
with query2 do
begin
close;
sql.Clear;
sql.Add('select QL_NO from QUESTION_QL where QL_TYPE=''0'' and QUES_ID='''+ary[a][0]+'''');
Prepare;
open
end;//with query2
y:=query2.RecordCount;
//showmessage(inttostr(y)); //測試用
//第二層迴圈經由第一層迴圈而得知問卷題數
for b:=1 to y do
begin
//第三層迴圈開始做選項比對,也就是第一份問卷的第一題的第一個選項有
//幾個人填答,在此會有完整結果
sql := 'INSERT INTO QUES_CRS_STA(QUES_ID,CRS_ID,TEA_ID,QS_NO,RESULT,QS_SUM1,QS_SUM2,QS_SUM3,QS_SUM4,QS_SUM5) VALUES';
Query3.SQL.Text := 'select QUES_ID,CRS_ID,TEA_ID,QS_NO,QS_SEL_ANS,TOTAL from EACH_QUES_QS_COUNT order by QUES_ID,CRS_ID,TEA_ID,QS_NO,QS_SEL_ANS';
Query3.Active := true;
While not Query3.eof do
begin
c[strtoint(Query3.FieldByName('QS_SEL_ANS').Value)] := Query3.FieldByName('TOTAL').Value;
if Query3.FieldByName('QS_SEL_ANS').Value = 5 then
begin
r:=((5*c[1])+(4*c[2])+(3*c[3])+(2*c[4])+(1*c[5]))/(c[1]+c[2]+c[3]+c[4]+c[5]);
sql := sql + '(' + Query3.Fields[0].AsString + ',' + Query3.Fields[1].AsString + ',' +
Query1.Fields[2].AsString + ',' + Query1.Fields[3].AsString + ',' + floatTostr(r)+
',' + intTostr(C[1]) + ',' + intTostr(C[2]) + ',' + intTostr(C[3]) + ',' +
intTostr(C[4]) + ',' + intTostr(C[5]) + '),'
end; // if
Query3.Next;
end;// while
sql := Copy(SQL,1,Length(SQL) - 1); // 除掉最後的
Query3.Active := false;
Query3.SQL.Text := SQL;
Query3.ExecSQL; // 一次過將所有結果 insert
end;//b
end;//a
引言: 我沒時間完全的看你的程式,但大致上有些建議給你可增加速度,簡單來說,你的程式執行慢主要是你處理 Queryx.sql 的手法而非 insert 執行的慢。即使你用 paradox table 亦不會有幫助的,可能反而變得更慢。 慢的主要原因 : 1. Prepare : Prepare 會耗用資源和時間,當一個Query只執行一次時,Prepare只會比不Prepare慢。但若一句SQL Statment會被重覆執行多次,則每次執行節省的時間,會使Prepare變得值得。可是你每次都執行一次便Clear了 SQL 重新加入,Prepare 又要重新耗用資源和時間,結果只會比不 Prepare 慢。而且,你好像沒用 UnPrepare 來釋放 Prepare 佔用了的資源,處理三千份問卷可能真的會令系統。 class="code"> procedure CalculateStat; var c : Array[1..5] of integer sql : string; begin sql := 'INSERT INTO QUES_CRS_STA (QUES_ID,CRS_ID,TEA_ID,QS_NO,RESULT,' 'QS_SUM1,QS_SUM2,QS_SUM3,QS_SUM4,QS_SUM5) VALUES ' Query1.SQL.Text := "select QUES_ID,CRS_ID,TEA_ID,QS_NO,QS_SEL_AS,TOTAL ' 'from EACH_QUES_QS_COUNT order by QUES_ID,CRS_ID,TEA_ID,QS_NO,QS_SEL_AS"; Query1.Active := true; While not Query1.eof do begin c[Query1.FieldByName('QS_SEL_AS').Value] := Query1.FieldByName('TOTAL').Value; if Query1.FieldByName('QS_SEL_AS').Value = 5 then // 該題完結,計算加權及加入一筆資料到 INSERT SQL begin r:=((5*c[1]) (4*c[2]) (3*c[3]) (2*c[4]) (1*c[5]))/(c[1] c[2] c[3] c[4] c[5]); sql := sql '(' Query1.Fields[0].AsString ',' Query1.Fields[1].AsString ',' Query1.Fields[2].AsString ',' Query1.Fields[3].AsString ',' StrToInt(r) ',' StrToInt(C[1]) ',' StrToInt(C[2]) ',' StrToInt(C[3]) ',' StrToInt(C[4]) ',' StrToInt(C[5]) '),' end // if Query1.Next; end;// while sql := Copy(SQL,1,Length(SQL) - 1); // 除掉最後的 , Query1.Active := false; Query1.SQL.Text := SQL; Query1.ExecSQL; // 一次過將所有結果 insert end; 我的做法是這樣的 1. select 時直接將所有相關欄位排列整齊,順著每問卷每題每答案排好 2. 一筆筆資料處理將每答案的 TOTAL 存入 c 陣列,完成一題後計算該題的加權並將該題的資料加入 Update sql 中 3. 所有題目完成後一次過 insert 所有資料到 database 這樣做只需一次 select 及一次 update,應會快很多,試試罷。 若我了解錯了你要做的請告知。 [修改: code 太長改短,sql := copy(...) 錯了更正] 發表人 - Justmade 於 2003/03/17 10:22:27 |
Justmade
版主 發表:94 回覆:1934 積分:2030 註冊:2003-03-12 發送簡訊給我 |
1. 貼程式碼請在程式碼前 加 [ code ] 後加 [ /code ] (除掉空白)
2. 每一筆記錄是 sql '(4442,21412,44.....),',尾用,去分開下一筆記錄,但最後 sql 尾部有 , 是不對的,所以要除掉該。
3. 我的程式碼是完全處理整個統計的,不單是處理第三層迴路,所以不能跟你本來的程式合著用啊。不過這是其於假設你每一問卷每題每個答案都有一筆記錄,即是說即使沒人答該答案都有一筆 TOTAL 為0 的記錄。 若沒人答的是沒記錄的話,就要加入一小段程式碼來控制每一題的轉接。
|
Justmade
版主 發表:94 回覆:1934 積分:2030 註冊:2003-03-12 發送簡訊給我 |
再看看你原來的程式後,發現我的價設好像是錯的,好像只當有人選該答案時才有資料罷?
下面修改過的版本應可應付
procedure CalculateStat; var c : Array[1..5] of integer sql, OQ, CQ : string; i : integer begin for i := 1 to 5 do c[i] := 0; //起始 array 資料 sql := 'INSERT INTO QUES_CRS_STA (QUES_ID,CRS_ID,TEA_ID,QS_NO,RESULT,' 'QS_SUM1,QS_SUM2,QS_SUM3,QS_SUM4,QS_SUM5) VALUES ' Query1.SQL.Text := "select QUES_ID,CRS_ID,TEA_ID,QS_NO,QS_SEL_AS,TOTAL ' 'from EACH_QUES_QS_COUNT order by QUES_ID,CRS_ID,TEA_ID,QS_NO,QS_SEL_AS"; Query1.Active := true; OQ := Query1.Fields[0].AsString '-' Query1.Fields[1].AsString '-' Query1.Fields[2].AsString '-' Query1.Fields[3].AsString While not Query1.eof do begin CQ := Query1.Fields[0].AsString '-' Query1.Fields[1].AsString '-' Query1.Fields[2].AsString '-' Query1.Fields[3].AsString if CQ <> OQ then // 該題完結,計算加權及加入一筆資料到 INSERT SQL begin r:=((5*c[1]) (4*c[2]) (3*c[3]) (2*c[4]) (1*c[5]))/(c[1] c[2] c[3] c[4] c[5]); sql := sql '(' Query1.Fields[0].AsString ',' Query1.Fields[1].AsString ',' Query1.Fields[2].AsString ',' Query1.Fields[3].AsString ',' StrToInt(r) ',' StrToInt(C[1]) ',' StrToInt(C[2]) ',' StrToInt(C[3]) ',' StrToInt(C[4]) ',' StrToInt(C[5]) '),'; for i := 1 to 5 do c[i] := 0; //重設 array 資料 OQ := CQ; end else // CQ = OQ 即還是在處理同一題目 begin c[Query1.FieldByName('QS_SEL_AS').Value] := Query1.FieldByName('TOTAL').Value; Query1.Next; end; // if end;// while sql := Copy(SQL,1,Length(SQL) - 1); // 除掉最後的 , Query1.Active := false; Query1.SQL.Text := SQL; Query1.ExecSQL; // 一次過將所有結果 insert end;原理: 1. select 時直接將所有相關欄位排列整齊,順著每問卷每題每答案排好,己包括你原來 Query1,2,3 的資料 2. 一筆筆資料處理將同一題的每答案的 TOTAL 存入 c 陣列中 3. 以OQ (Old Question) 及 CQ (Current question) 來驗證分辨是否正在處理同一問題,若 QUES_ID,CRS_ID,TEA_ID,QS_NO 任一欄位改變即是完成一題進到下一題,這時便計算該題的加權並將該題的資料加入 Update sql 中 4. 所有題目完成後一次過 insert 所有資料到 database |
challenge
一般會員 發表:14 回覆:41 積分:11 註冊:2002-10-08 發送簡訊給我 |
謝謝你一直幫我解答…^^ 我想請問的是一開始的for i := 1 to 5 do及中間的for迴圈用意是:若其中一個選項沒人填的話,其值會預設為0嗎?
目前我執行的話…一開始run了一下下後就會出現「Unknown column 'cyut0002003022205'in'field list'」這個錯誤訊息,不太了解什麼意思,cyut0002003022205是我其中的一個問卷編號,也都有資料存在…
好像是在最後執行Query1.ExecSQL;時發生的…
procedure TForm1.Button1Click(Sender: TObject); var c : Array[1..5] of integer; sql,OQ,CQ : string; i,j : integer; r : double; begin for i := 1 to 5 do begin c[i] := 0; //起始 array 資料 end;//for sql := 'INSERT INTO QUES_CRS_STA(CRS_ID,TEA_ID,QUES_ID,QS_NO,RESULT,QS_SUM1,QS_SUM2,QS_SUM3,QS_SUM4,QS_SUM5) VALUES'; Query1.SQL.Text := 'select CRS_ID,TEA_ID,QUES_ID,QS_NO,QS_SEL_ANS,TOTAL from EACH_QUES_QS_COUNT order by QUES_ID,CRS_ID,TEA_ID,QS_NO,QS_SEL_ANS'; Query1.Active := true; OQ := Query1.Fields[0].AsString '-' Query1.Fields[1].AsString '-' Query1.Fields[2].AsString '-' Query1.Fields[3].AsString; While not Query1.eof do begin CQ := Query1.Fields[0].AsString '-' Query1.Fields[1].AsString '-' Query1.Fields[2].AsString '-' Query1.Fields[3].AsString; if CQ <> OQ then begin r:=((5*c[1]) (4*c[2]) (3*c[3]) (2*c[4]) (1*c[5]))/(c[1] c[2] c[3] c[4] c[5]); sql := sql '(' Query1.Fields[0].AsString ',' Query1.Fields[1].AsString ',' Query1.Fields[2].AsString ',' Query1.Fields[3].AsString ',' floatTostr(r) ',' intTostr(C[1]) ',' intTostr(C[2]) ',' intTostr(C[3]) ',' intTostr(C[4]) ',' intTostr(C[5]) '),'; for i := 1 to 5 do begin c[i] := 0; //重設 array 資料 end;//for OQ := CQ; end else // CQ = OQ 即還是在處理同一題目 begin c[strtoint(Query1.FieldByName('QS_SEL_ANS').Value)] := Query1.FieldByName('TOTAL').Value; Query1.Next; end; // if end;// while sql := Copy(SQL,1,Length(SQL) - 1); // 除掉最後的 , Query1.Active := false; Query1.SQL.Text := SQL; Query1.ExecSQL; // 一次過將所有結果 insert end;這樣的確快好多哦…^^ 引言: 再看看你原來的程式後,發現我的價設好像是錯的,好像只當有人選該答案時才有資料罷? 下面修改過的版本應可應付 |
Justmade
版主 發表:94 回覆:1934 積分:2030 註冊:2003-03-12 發送簡訊給我 |
引言: 我想請問的是一開始的for i := 1 to 5 do及中間的for迴圈用意是:若其中一個選項沒人填的話,其值會預設為0嗎?對丫 引言: 目前我執行的話…一開始run了一下下後就會出現「Unknown column 'cyut0002003022205'in'field list'」這個錯誤訊息,不太了解什麼意思,cyut0002003022205是我其中的一個問卷編號,也都有資料存在… 好像是在最後執行Query1.ExecSQL;時發生的…問題出在 : sql := sql '(' Query1.Fields[0].AsString ',' Query1.Fields[1].AsString ',' Query1.Fields[2].AsString ',' Query1.Fields[3].AsString ',' IntToStr(r) ',' IntToStr(C[1]) ',' IntToStr(C[2]) ',' IntToStr(C[3]) ',' IntToStr(C[4]) ',' IntToStr(C[5]) '),';因為這是以為你的 QUES_ID,CRS_ID,TEA_ID 是數字欄位。但現在看來是文字欄位罷。換成以下的罷 sql := sql '(''' Query1.Fields[0].AsString ''',''' Query1.Fields[1].AsString ''',''' Query1.Fields[2].AsString ''',' Query1.Fields[3].AsString ',' IntToStr(r) ',' IntToStr(C[1]) ',' IntToStr(C[2]) ',' IntToStr(C[3]) ',' IntToStr(C[4]) ',' IntToStr(C[5]) '),';看來我看錯了不少東西,還把所有 IntToStr 倒轉成了 StrToInt ,真不小心 成功的話請告知 |
Justmade
版主 發表:94 回覆:1934 積分:2030 註冊:2003-03-12 發送簡訊給我 |
對不起,突然發覺有個大錯誤,程式會將先一題的結果以新一題的問題號記錄,因為當 OQ <> CQ 時,QUES_ID,CRS_ID,TEA_ID 等已變成新一題的資料了。 改正 :
procedure CalculateStat; var c : Array[1..5] of integer sql, OQ, CQ : string; i : integer begin for i := 1 to 5 do c[i] := 0; //起始 array 資料 sql := 'INSERT INTO QUES_CRS_STA (QUES_ID,CRS_ID,TEA_ID,QS_NO,RESULT,' 'QS_SUM1,QS_SUM2,QS_SUM3,QS_SUM4,QS_SUM5) VALUES ' Query1.SQL.Text := "select QUES_ID,CRS_ID,TEA_ID,QS_NO,QS_SEL_AS,TOTAL ' 'from EACH_QUES_QS_COUNT order by QUES_ID,CRS_ID,TEA_ID,QS_NO,QS_SEL_AS"; Query1.Active := true; OQ := '(' Query1.Fields[0].AsString ',' Query1.Fields[1].AsString ',' Query1.Fields[2].AsString ',' Query1.Fields[3].AsString While not Query1.eof do begin CQ := '(' Query1.Fields[0].AsString ',' Query1.Fields[1].AsString ',' Query1.Fields[2].AsString ',' Query1.Fields[3].AsString if CQ <> OQ then // 該題完結,計算加權及加入一筆資料到 INSERT SQL begin r:=((5*c[1]) (4*c[2]) (3*c[3]) (2*c[4]) (1*c[5]))/(c[1] c[2] c[3] c[4] c[5]); sql := sql OQ ',' StrToInt(r) ',' StrToInt(C[1]) ',' StrToInt(C[2]) ',' StrToInt(C[3]) ',' StrToInt(C[4]) ',' StrToInt(C[5]) '),'; for i := 1 to 5 do c[i] := 0; //重設 array 資料 OQ := CQ; end else // CQ = OQ 即還是在處理同一題目 begin c[Query1.FieldByName('QS_SEL_AS').Value] := Query1.FieldByName('TOTAL').Value; Query1.Next; end; // if end;// while sql := Copy(SQL,1,Length(SQL) - 1); // 除掉最後的 , Query1.Active := false; Query1.SQL.Text := SQL; Query1.ExecSQL; // 一次過將所有結果 insert end;這個改用 update SQL 的一部份做 OQ / CQ ,比對功能一樣但當 OQ <> CQ 時可直接用 OQ 填入 SQL ,除改正錯誤外,程式應再加快一丁點。 唉...我的腦袋模擬除錯器越來越不成了..... |
challenge
一般會員 發表:14 回覆:41 積分:11 註冊:2002-10-08 發送簡訊給我 |
哇哈哈…真的可以了…而且非常快哦…只花了十秒鐘就ok了…
真是非常感激…跟我本來的程式真是差太多了…^^"
只是…它有一個問題就是…最後一份問卷的最後一題不會產生… <>< face="Verdana, Arial, Helvetica">引言:
對不起,突然發覺有個大錯誤,程式會將先一題的結果以新一題的問題號記錄,因為當 OQ <> CQ 時,QUES_ID,CRS_ID,TEA_ID 等已變成新一題的資料了。 這個改用 update SQL 的一部份做 OQ / CQ ,比對功能一樣但當 OQ <> CQ 時可直接用 OQ 填入 SQL ,除改正錯誤外,程式應再加快一丁點。 唉...我的腦袋模擬除錯器越來越不成了.....< > 別這麼說…我覺得你的模擬除錯器非常強呢!< >
|
Justmade
版主 發表:94 回覆:1934 積分:2030 註冊:2003-03-12 發送簡訊給我 |
唉又一個漏洞,再再再改正 :
procedure CalculateStat; var c : Array[1..5] of integer sql, OQ, CQ : string; i : integer begin for i := 1 to 5 do c[i] := 0; //起始 array 資料 sql := 'INSERT INTO QUES_CRS_STA (QUES_ID,CRS_ID,TEA_ID,QS_NO,RESULT,' 'QS_SUM1,QS_SUM2,QS_SUM3,QS_SUM4,QS_SUM5) VALUES ' Query1.SQL.Text := "select QUES_ID,CRS_ID,TEA_ID,QS_NO,QS_SEL_AS,TOTAL ' 'from EACH_QUES_QS_COUNT order by QUES_ID,CRS_ID,TEA_ID,QS_NO,QS_SEL_AS"; Query1.Active := true; OQ := '(' Query1.Fields[0].AsString ',' Query1.Fields[1].AsString ',' Query1.Fields[2].AsString ',' Query1.Fields[3].AsString While not Query1.eof do begin CQ := '(' Query1.Fields[0].AsString ',' Query1.Fields[1].AsString ',' Query1.Fields[2].AsString ',' Query1.Fields[3].AsString if CQ <> OQ then // 該題完結,計算加權及加入一筆資料到 INSERT SQL begin r:=((5*c[1]) (4*c[2]) (3*c[3]) (2*c[4]) (1*c[5]))/(c[1] c[2] c[3] c[4] c[5]); sql := sql OQ ',' StrToInt(r) ',' StrToInt(C[1]) ',' StrToInt(C[2]) ',' StrToInt(C[3]) ',' StrToInt(C[4]) ',' StrToInt(C[5]) '),'; for i := 1 to 5 do c[i] := 0; //重設 array 資料 OQ := CQ; end else // CQ = OQ 即還是在處理同一題目 begin c[Query1.FieldByName('QS_SEL_AS').Value] := Query1.FieldByName('TOTAL').Value; Query1.Next; end; // if end;// while sql := sql OQ ',' StrToInt(r) ',' StrToInt(C[1]) ',' StrToInt(C[2]) ',' StrToInt(C[3]) ',' StrToInt(C[4]) ',' StrToInt(C[5]) ')';十秒不錯哦 |
challenge
一般會員 發表:14 回覆:41 積分:11 註冊:2002-10-08 發送簡訊給我 |
|
Justmade
版主 發表:94 回覆:1934 積分:2030 註冊:2003-03-12 發送簡訊給我 |
本站聲明 |
1. 本論壇為無營利行為之開放平台,所有文章都是由網友自行張貼,如牽涉到法律糾紛一切與本站無關。 2. 假如網友發表之內容涉及侵權,而損及您的利益,請立即通知版主刪除。 3. 請勿批評中華民國元首及政府或批評各政黨,是藍是綠本站無權干涉,但這裡不是政治性論壇! |