線上訂房服務-台灣趴趴狗聯合訂房中心
發文 回覆 瀏覽次數:3150
推到 Plurk!
推到 Facebook!

大量資料存取效能不高之解決方法?

答題得分者是:Justmade
challenge
一般會員


發表:14
回覆:41
積分:11
註冊:2002-10-08

發送簡訊給我
#1 引用回覆 回覆 發表時間:2003-03-16 22:08:15 IP:211.74.xxx.xxx 未訂閱
各位前輩您好…因我要做統計計算…需處理上萬筆資料…本來的做法是採用 邊算邊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

發送簡訊給我
#2 引用回覆 回覆 發表時間:2003-03-17 00:02:49 IP:61.221.xxx.xxx 未訂閱
Hi, 先針對你的第一個問題, 統計計算的資料是否有相依性的問題. 若是沒有的話, 即使速度慢, 可以分次計算應該是沒有問題的, 但不 知速度慢的原因為何, 若是卡在 insert 上面的話, 即使你在 client 端先作好再 insert 的話, 應該也不會改善的. 要看發生速度慢的原 因為何才能決定這樣的作法是否合適. 第二個 paradox 產生型態不符的問題, 可否列出錯誤訊息, 另外你的 程式碼的部分沒有什麼問題, 是否 all 陣列的型態有問題, 或是 table 的欄位型態不是字串呢? 可否列出較完整的說明, 讓大家幫你看看.
challenge
一般會員


發表:14
回覆:41
積分:11
註冊:2002-10-08

發送簡訊給我
#3 引用回覆 回覆 發表時間:2003-03-17 02:07:49 IP:211.74.xxx.xxx 未訂閱
引言: 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

發送簡訊給我
#4 引用回覆 回覆 發表時間:2003-03-17 10:02:26 IP:218.16.xxx.xxx 未訂閱
我沒時間完全的看你的程式,但大致上有些建議給你可增加速度,簡單來說,你的程式執行慢主要是你處理 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

發送簡訊給我
#5 引用回覆 回覆 發表時間:2003-03-17 10:10:35 IP:61.219.xxx.xxx 未訂閱
1. 運用 Store Procedure (MySQL 4.x 不知有沒有). 2. 彙算用的大量原始資料, 避免 open 到前端來.    ( 多運用 SQL : sum / avg 等 function, 讓 DB Server 先做初步的收整 ) 3. po 上原始碼時請看 http://delphi.ktop.com.tw/topic.php?TOPIC_ID=7326    比較易讀喔 /*
Justmade
版主


發表:94
回覆:1934
積分:2030
註冊:2003-03-12

發送簡訊給我
#6 引用回覆 回覆 發表時間:2003-03-17 10:29:41 IP:218.16.xxx.xxx 未訂閱
引言: 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

發送簡訊給我
#7 引用回覆 回覆 發表時間:2003-03-17 12:19:55 IP:211.76.xxx.xxx 未訂閱
可否將你的 table schema 先放上來, 或是簡單說明一下. 再將你要的統計結果的 criteria 告訴大家, 這樣比較快. 你的程式用了太多不必要的迴圈和判斷式, 導致效能不高, 雖然 mysql 不支援 stored procedure, 但仍可用 sql command 來處理資料, 以減少在 client 計算的時間. 誠如前面幾位前輩的說明, 利用 server 先進行處理才是 解決之道!!
challenge
一般會員


發表:14
回覆:41
積分:11
註冊:2002-10-08

發送簡訊給我
#8 引用回覆 回覆 發表時間:2003-03-17 16:55:32 IP:211.74.xxx.xxx 未訂閱
謝謝你幫我將程式做了詳細的分析…難怪我的程式跑那麼慢…^^" 我大致上將我的程式更改如下…只是為何會出現「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

發送簡訊給我
#9 引用回覆 回覆 發表時間:2003-03-17 17:14:57 IP:218.16.xxx.xxx 未訂閱
1. 貼程式碼請在程式碼前 加 [ code ] 後加 [ /code ] (除掉空白) 2. 每一筆記錄是 sql '(4442,21412,44.....),',尾用,去分開下一筆記錄,但最後 sql 尾部有 , 是不對的,所以要除掉該。 3. 我的程式碼是完全處理整個統計的,不單是處理第三層迴路,所以不能跟你本來的程式合著用啊。不過這是其於假設你每一問卷每題每個答案都有一筆記錄,即是說即使沒人答該答案都有一筆 TOTAL 為0 的記錄。 若沒人答的是沒記錄的話,就要加入一小段程式碼來控制每一題的轉接。
Justmade
版主


發表:94
回覆:1934
積分:2030
註冊:2003-03-12

發送簡訊給我
#10 引用回覆 回覆 發表時間:2003-03-17 17:41:35 IP:218.16.xxx.xxx 未訂閱
再看看你原來的程式後,發現我的價設好像是錯的,好像只當有人選該答案時才有資料罷? 下面修改過的版本應可應付    
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

發送簡訊給我
#11 引用回覆 回覆 發表時間:2003-03-18 01:14:21 IP:211.74.xxx.xxx 未訂閱
謝謝你一直幫我解答…^^ 我想請問的是一開始的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

發送簡訊給我
#12 引用回覆 回覆 發表時間:2003-03-18 08:24:16 IP:218.16.xxx.xxx 未訂閱
引言: 我想請問的是一開始的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

發送簡訊給我
#13 引用回覆 回覆 發表時間:2003-03-18 14:02:44 IP:218.16.xxx.xxx 未訂閱
對不起,突然發覺有個大錯誤,程式會將先一題的結果以新一題的問題號記錄,因為當 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

發送簡訊給我
#14 引用回覆 回覆 發表時間:2003-03-18 15:34:43 IP:211.74.xxx.xxx 未訂閱
哇哈哈…真的可以了…而且非常快哦…只花了十秒鐘就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

發送簡訊給我
#15 引用回覆 回覆 發表時間:2003-03-18 15:53:32 IP:218.16.xxx.xxx 未訂閱
唉又一個漏洞,再再再改正 :
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])   ')';
  sql := Copy(SQL,1,Length(SQL) - 1); // 除掉最後的 ,//沒有最後,了
  Query1.Active := false;
  Query1.SQL.Text := SQL;
  Query1.ExecSQL; // 一次過將所有結果 insert
end;
十秒不錯哦
challenge
一般會員


發表:14
回覆:41
積分:11
註冊:2002-10-08

發送簡訊給我
#16 引用回覆 回覆 發表時間:2003-03-19 11:56:26 IP:211.74.xxx.xxx 未訂閱
耶!! 都 > 謝謝你喔…^^ <>< face="Verdana, Arial, Helvetica">引言: 唉又一個漏洞,再再再改正 : 十秒不錯哦 < face="Verdana, Arial, Helvetica">
Justmade
版主


發表:94
回覆:1934
積分:2030
註冊:2003-03-12

發送簡訊給我
#17 引用回覆 回覆 發表時間:2003-03-19 12:15:39 IP:218.16.xxx.xxx 未訂閱
多練習多看別人甚樣做多想想不同的方法,你一定能做得到的 
系統時間:2024-06-29 16:09:00
聯絡我們 | Delphi K.Top討論版
本站聲明
1. 本論壇為無營利行為之開放平台,所有文章都是由網友自行張貼,如牽涉到法律糾紛一切與本站無關。
2. 假如網友發表之內容涉及侵權,而損及您的利益,請立即通知版主刪除。
3. 請勿批評中華民國元首及政府或批評各政黨,是藍是綠本站無權干涉,但這裡不是政治性論壇!