DBGrid 插入資料 |
答題得分者是:cancer
|
monkeyhung
一般會員 發表:51 回覆:55 積分:21 註冊:2006-12-16 發送簡訊給我 |
|
P.D.
版主 發表:603 回覆:4038 積分:3874 註冊:2006-10-31 發送簡訊給我 |
dbgrid 只是一個前端的data顯示器, 不具有各式資料的編輯, 而你問到的問題, 可大可小
對於"序號"的處置, 端看你如何定義"序號"的給號方式才能決定程式要如何走向, 不妨搜尋一下本站"序號"應可看到不少討論 至於如何插入序號, 必須直接對資料庫下手, 而不是dbgrid ===================引 用 monkeyhung 文 章=================== 各位大大好: ??? 小弟目前有使用dbgrid來新增、修改、刪除資料庫裡的資料, 然而小弟規劃的資料表中是有使用到「序號」這個欄位, 當使用者新增時就會自動給序一個序號值,而刪除資料後同時 序號也會進行重排的動作。但因為目前使用者有遇到一個問題, 當他輸入完整個資料後,發現輸入的資料之中需要插入一筆資料, 這樣子的話,dbgrdi該如何來達到這個目的呢?? 因為user是希望到時dbgrid重新查詢出來或列印資料時, 是根據他當初所輸入、插入的順序呈現 。 |
lsh19871112
一般會員 發表:2 回覆:8 積分:7 註冊:2010-09-06 發送簡訊給我 |
|
monkeyhung
一般會員 發表:51 回覆:55 積分:21 註冊:2006-12-16 發送簡訊給我 |
|
pedro
尊榮會員 發表:152 回覆:1187 積分:892 註冊:2002-06-12 發送簡訊給我 |
Hi
對不起插花一下,建議你去看討論區裡所有dbgrid關於"流水號","序號"的資料 http://delphi.ktop.com.tw/board.php?cid=30&fid=1498..&tid=95268 http://delphi.ktop.com.tw/board.php?cid=30&fid=66&tid=100180 ===================引 用 monkeyhung 文 章=================== 各位大大好: ??? 小弟目前有使用dbgrid來新增、修改、刪除資料庫裡的資料, 然而小弟規劃的資料表中是有使用到「序號」這個欄位, 當使用者新增時就會自動給序一個序號值,而刪除資料後同時 序號也會進行重排的動作。但因為目前使用者有遇到一個問題, 當他輸入完整個資料後,發現輸入的資料之中需要插入一筆資料, 這樣子的話,dbgrdi該如何來達到這個目的呢?? 因為user是希望到時dbgrid重新查詢出來或列印資料時, 是根據他當初所輸入、插入的順序呈現 。 |
P.D.
版主 發表:603 回覆:4038 積分:3874 註冊:2006-10-31 發送簡訊給我 |
任何給值最大號的方式都會有漏洞與不可預期的問題, 沒有人可以100%保證取到的號碼一定ok,
如果這個操作在單機上或許保證值高一點, 但如果是多人存取時, 怎麼死的都不知道 所以之前有人也問到這個問題, 我一向的回答是要以單值做為排序鍵值是不太可行 因此我提到的序號, 是指你要拿序號做什麼用, 目的在那裡? 考慮用 index 方式來處理資料的排序才是標準的作法 再者, 如果你這樣寫, 假設資料庫有10萬記錄, 你每插入一筆, 就要全部異動重排, 保證資料庫沒用幾次一定會crash掉! 另外, 以前早期dbase 資料庫系統是具有 insert及 append 的功能, 但現在的sql資料庫 都已只有append功能, 沒有insert功能, 所以不建議你用這種方法操作資料庫 ===================引 用 monkeyhung 文 章=================== 目前小弟所採取的是當Query? NewRecord時就先給予一個最大值的序號, 當Query AfterDelete後又再把所有序號重新排序, 雖然當Query是在編輯狀態,當按下insert鍵時,dbgrid可以插入一個空白 列供輸入,但似乎只要Query 一post後此筆資料就會馬上被放到最後一筆去了, 這樣話,即使我再做重新編排序號的工作時,也會因為此資料是在最後一筆, 而給予最大值的序號。 |
monkeyhung
一般會員 發表:51 回覆:55 積分:21 註冊:2006-12-16 發送簡訊給我 |
各位大大:
那如果我們暫且先不討論「序號」重排的目題,就單獨以在dbgrid中插入一筆資料來討論, 因為目前就算在dbgrid中按下insert鍵後雖然dbgrid是會產生一個空白列來供user輸入資料, 但是如同小弟先前所說的,只要query一移動的話,此筆剛insert的資料馬上就會被放到最後一筆。 這樣的結果是不是如同PD大所說的那樣「但現在的sql資料庫都已只有append功能, 沒有insert功能」嗎?? 所以才會造成說即使用insert的方式,資料還是都放在query最後一筆呢?? |
sryang
尊榮會員 發表:39 回覆:762 積分:920 註冊:2002-06-27 發送簡訊給我 |
|
P.D.
版主 發表:603 回覆:4038 積分:3874 註冊:2006-10-31 發送簡訊給我 |
其實重點應該在於討論你要insert的目的在那裡, 再來討論後面要如何做?
===================引 用 monkeyhung 文 章=================== 各位大大: ??? 那如果我們暫且先不討論「序號」重排的目題,就單獨以在dbgrid中插入一筆資料來討論, 因為目前就算在dbgrid中按下insert鍵後雖然dbgrid是會產生一個空白列來供user輸入資料, 但是如同小弟先前所說的,只要query一移動的話,此筆剛insert的資料馬上就會被放到最後一筆。 這樣的結果是不是如同PD大所說的那樣「但現在的sql資料庫都已只有append功能, 沒有insert功能」嗎?? 所以才會造成說即使用insert的方式,資料還是都放在query最後一筆呢?? |
monkeyhung
一般會員 發表:51 回覆:55 積分:21 註冊:2006-12-16 發送簡訊給我 |
PD大大:
user的問題點是在於說,當初他輸入的資料如下 A B D E F G 後來發現少打了一筆C,想要在B、D之間把C插入。 但如果讓user在dbgrid最後一筆來輸入C資料時,待存完檔後再來重新排序的話, 因為橫向欄位有很多個,user也說不出所要order by的欄位順序, 所以才會想利用「序號」來達到資料排序的目的 ===================引 用 P.D. 文 章=================== 其實重點應該在於討論你要insert的目的在那裡, 再來討論後面要如何做? ===================引 用 monkeyhung 文 章=================== 各位大大: ??? 那如果我們暫且先不討論「序號」重排的目題,就單獨以在dbgrid中插入一筆資料來討論, 因為目前就算在dbgrid中按下insert鍵後雖然dbgrid是會產生一個空白列來供user輸入資料, 但是如同小弟先前所說的,只要query一移動的話,此筆剛insert的資料馬上就會被放到最後一筆。 這樣的結果是不是如同PD大所說的那樣「但現在的sql資料庫都已只有append功能, 沒有insert功能」嗎?? 所以才會造成說即使用insert的方式,資料還是都放在query最後一筆呢?? |
herbert2
尊榮會員 發表:58 回覆:640 積分:894 註冊:2004-04-16 發送簡訊給我 |
|
P.D.
版主 發表:603 回覆:4038 積分:3874 註冊:2006-10-31 發送簡訊給我 |
1.其實這個問題使用 index 或 order by 解決就好, 根本就不要考慮 insert 方式
2.客戶不知道要 order by 那些, 那你就寫一支可以 order by 任意欄位的設計, 讓客戶想排那裡就排那裡 3.序號的部份, 就如上面樓主所說, 序號由電腦自動累加, 但可以修改, 不過這種方式比較適用於開單的明細中的各項品項使用, 並不適用於全體資料庫取號, 因為你要考量資料量的大小, 萬一有十幾萬筆, 那取號位數要多長啊? 所以最好的方式就是你自己想一個方式可以經由 order by 排出客戶想要的順序的出來, 這就必須你自己去研究客戶資料庫的欄位, 有沒有可以組合出排列的! ===================引 用 monkeyhung 文 章=================== PD大大: user的問題點是在於說,當初他輸入的資料如下 A B D E F G 後來發現少打了一筆C,想要在B、D之間把C插入。 但如果讓user在dbgrid最後一筆來輸入C資料時,待存完檔後再來重新排序的話, 因為橫向欄位有很多個,user也說不出所要order by的欄位順序, 所以才會想利用「序號」來達到資料排序的目的 |
herbert2
尊榮會員 發表:58 回覆:640 積分:894 註冊:2004-04-16 發送簡訊給我 |
|
cancer
高階會員 發表:58 回覆:319 積分:190 註冊:2004-07-31 發送簡訊給我 |
Monkey大,您講的那個,不叫序號,叫做項次,項次1,項次 2,項次 3...。您的需求,我們公司的程式裡面普遍使用著,那是一個不好弄的東西。
1.開一個整數欄位,例如 [項次] 2.用 DataSet.Append 來新增,不能用 Insert(),要在 DBGrid.OnKeyDown 排除 Insert 鍵。 3.OnNewRecord 時,DataSet.FieldByName('項次').AsInteger := DataSet.RecordCount 1; 4.存檔後重新讀取,用 order by 項次 以上是正常情形,沒有插入項次的問題。 var k : integer; if (DataSet.State = dsInsert) or (DataSet.RecNo = DataSet.Recordcount) then DataSet.Append // 在最後一筆, Append 就好,不用脫褲子放屁 else begin k := DataSet.FieldByName('項次').AsInteger; // 插入當前游標這一筆,記起來 //第一圈空出當前項次 DataSet.DisableControls; DataSet.Last; // 迴圈要反過來(有 Sort 的關係) while not DataSet.BOF do // LockType 必須 ltBatchoptimistic 或類似功能 begin if DataSet.FieldByName('項次').AsInteger >= k then // 從現在位置開始,全部加一 begin DataSet.Edit; DataSet.FieldByName('項次').AsInteger := DataSet.FieldByName('項次').AsInteger 1; DataSet.Post; end; DataSet.Prior; end; DataSet.First; //新增明細 DataSet.Sort := ''; // 先解除內部排序 DataSet.Append; // 會加在最後面(所以要 DisableControls,讓使用者看不到發生甚麼) DataSet.FieldByName('項次').AsInteger := k; // k = 要新增的項次編號 DataSet.Post; DataSet.Sort := '項次'; // 新增列會排在正確位置 DataSet.Locate('項次', Variant(k), []); // 指回原先位置供輸入 DataSet.EnableControls; end; 關鍵在於利用了 DataSet.Sort 的功能,用了 Sort,DataSet.Insert() 會異常,一律用 Append()。 這只是插入而已,有插入,就可能會亂掉,還要提供重排的功能,這要再加一個整數欄位來輔助。 程式碼比這裡複雜,我是抽出來的,可能會漏掉,先試看看,自己摸一摸,不行再貼文告訴我。
編輯記錄
cancer 重新編輯於 2011-04-22 07:04:43, 註解 無‧
|
herbert2
尊榮會員 發表:58 回覆:640 積分:894 註冊:2004-04-16 發送簡訊給我 |
項次若不准 User 修改,通常 User 會很困擾。
例如:客戶來張15個品項的詢價單,User Key-In 報價單時漏掉 12th 項; 當然,可以補在最後,但如此一來便會與詢價單的順序不同。 有些客戶並不挑剔,但有些客戶會很在意甚至退回;那要不要准 User 改項次呢? 交易主檔資料錄可能數千萬筆以上,若 Unique Key 需用到數個欄位,且欄長又較長, 則以 Sequence (int 8 or 10 位) 做 Unique Key 是常用的方法,以便 Detail 檔直接用 Sequence 欄與 Master 檔 Join。 只是,通常 Sequence 欄是不准 User 改的;但若真沒法 Order By,可能也只好開放修改了。 若要准 User 非常彈性的挑選資料及排序,小弟上文所提供的人機界面,可做非常彈性的安排; 例如:挑出各縣市各有不同的交易額標準的大客戶....等,或是轉換成 SubQuery 的條件等。 若有興趣,不妨可自行開發看看! |
cancer
高階會員 發表:58 回覆:319 積分:190 註冊:2004-07-31 發送簡訊給我 |
項次不應該由使用者修改,要由程式決定,因為項次必須連號,就是
1.不可重複 2.不可有縫隙 3.必須照 1,2,3 的順序 如果是漏打,插入項次就搞定,打錯位置才麻煩,12th 打到 15th去,要把 15th 移到 12th。 所以,程式如果提插入項次的功能,就要同時提供一系列的同類功能,才能完整,如下: 1.插入項次 2.項次亂掉要重排 3.刪除項次不是最後一筆的話,要自動重排項次 4.提供單一項次的位置調整功能 5.提供批次的項次調整功能(打開另一畫面,調好按確定) 6.提供項次複製新增的功能,例如把 12th 複製並插入 15th,15th及以下的往下推 以上的項次處理功能,使用者很常用到的,輸入順序必須跟手上頭單據的順序一致,這是基本要求,使用者很常要比對單據上的內容跟 DBGrid 的內容是否一致,順序如果不一致,對單的時間可能比打單還要久。有時候客戶給了 10 個項次,打單人沒有漏打,順序都正確,好死不死,客戶又傳 e-mail 來說少給了一條,要放到 5th 裡面,這怎麼辦?如果程式沒有項次處理能力,就只好刪除 6th 開始的資料,在 5th 處開始重打,又聽到罵客戶的聲音啦。 微軟和 Delphi 都一直更版,宣稱產品功能愈來愈強大,開發人員又多方便,但這種項次處理能力,我看別人十幾年寫的資料庫軟體早就有了,而微軟和 Delphi 的介面元件都沒有這些項次處理能力,就連要在 DBGrid 上面輸入 Memo 欄位,我們都要另外寫程式碼來達成。開發環境的確功能愈來愈強,但我們要的基本功能,卻永遠不會在新功能裡面。 不過也好,這樣開發人員才能保住飯碗,開發環境太強,隨便找個剛畢業的,就能寫出功能完整的程式,我們就可以退休了。 |
herbert2
尊榮會員 發表:58 回覆:640 積分:894 註冊:2004-04-16 發送簡訊給我 |
項次當然不可重複,但跳號其實無妨。
例如:詢價單雖有15品項,但可依詢價單項次,只對其中部分項次報價,又何妨? 若印表時,硬要將跳號項次自動改為連號印出,其實也毫無技術困難的。 當然,若同時提供 Append 與 Insert 功能,項次是可由程式自動重編的,例如:會計傳票的借貸項次。 但有些 User 要求須准跳號者,若不准 User 自行修改,可能就不符 User 的需求了。 當 User 擬將資料存檔時,程式不都會檢查 Unique Key? 若 User 故意要 Key 重複的項次,想必沒有一個程式會准他存檔吧! |
cancer
高階會員 發表:58 回覆:319 積分:190 註冊:2004-07-31 發送簡訊給我 |
我看過別人寫的程式,項次不能直接修改,但提供一個畫面列出所有明細資料,有一個欄位供輸入項次,可以輸入重複項次值,還可以不輸入,按確定後,程式會替每一筆明細填入項次值,如果有相同,會放在一起,但順序比照原來的順序。
原本 指定 1 2 3 1 4 1 5 6 5 先排成 3,4,1,2,6,5,再重填項次值 1-6。 ===================引 用 herbert2 文 章=================== 項次當然不可重複,但跳號其實無妨。 例如:詢價單雖有15品項,但可依詢價單項次,只對其中部分項次報價,又何妨? 若印表時,硬要將跳號項次自動改為連號印出,其實也毫無技術困難的。 當然,若同時提供 Append 與 Insert 功能,項次是可由程式自動重編的,例如:會計傳票的借貸項次。 但有些 User 要求須准跳號者,若不准 User 自行修改,可能就不符 User 的需求了。 當 User 擬將資料存檔時,程式不都會檢查 Unique Key? 若 User 故意要 Key 重複的項次,想必沒有一個程式會准他存檔吧! |
monkeyhung
一般會員 發表:51 回覆:55 積分:21 註冊:2006-12-16 發送簡訊給我 |
感謝各位大大的回答
後來小弟和同事討論了一番 所採取的做法如下 [code delphi] //**定義公堿變數 var xDBGridKey,xSeq_G,xSeq_H,xModify:String; procedure TFABCD.Query_DNewRecord(DataSet: TDataSet); begin if xDBGridKey='Insert' then begin Query_D.FieldByname('Seq').AsString:=Format('%.3d',[Strtoint(xSeq_G)]); xSeq_H:=xSeq_G; xmodify:='1'; xDBGridKey:=''; end; end; procedure TFABCD.Query_DBeforeScroll(DataSet: TDataSet); begin xSeq_G:=DataSet.FieldByName('Seq').AsString; end; procedure TFABCD.Query_DAfterPost(DataSet: TDataSet); begin if xModify='1' then begin xModify :=''; Query_D.Edit; _SeqRefresh;//**自動編號 end; end; procedure TFABCD._SeqRefresh; var i,j:integer; xPoint : TBookMark; begin try i:=0; Query_D.DisableControls; Query_D.First; j:=StrToInt(xSeq_G); while Not Query_D.Eof do begin Query_D.Edit; if Query_D.FieldByName('Seq').AsString>=Format('%.3d',[Strtoint(xSeq_H)]) then begin if Query_D.FieldByName('Seq').AsString=Format('%.3d',[Strtoint(xSeq_H)]) then begin i:=i 1; if i> 1 then begin Query_D.Next; Continue; end; end; inc(j); Query_D.FieldByName('Seq').AsString := Format('%.3d',[j]); Query_D.Post; end; Query_D.Next; end; finally Query_D.EnableControls; end; end; procedure TFABCD.DBGrid_DKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState); begin if Key=VK_Insert then xDBGridKey:='Insert'; end; [/code] |
bestlong
站務副站長 發表:126 回覆:734 積分:512 註冊:2002-10-19 發送簡訊給我 |
這樣處理會有問題的
事件 Query_DAfterPost 會呼叫 _SeqRefresh 然後 _SeqRefresh 內又直接用 Query_D.Post 又觸發事件 Query_DAfterPost 會慘喔 ===================引 用 monkeyhung 文 章=================== 感謝各位大大的回答 後來小弟和同事討論了一番 所採取的做法如下 [code delphi] //**定義公堿變數 var xDBGridKey,xSeq_G,xSeq_H,xModify:String; procedure TFABCD.Query_DNewRecord(DataSet: TDataSet); begin if xDBGridKey='Insert' then begin Query_D.FieldByname('Seq').AsString:=Format('%.3d',[Strtoint(xSeq_G)]); xSeq_H:=xSeq_G; xmodify:='1'; xDBGridKey:=''; end; end; procedure TFABCD.Query_DBeforeScroll(DataSet: TDataSet); begin xSeq_G:=DataSet.FieldByName('Seq').AsString; end; procedure TFABCD.Query_DAfterPost(DataSet: TDataSet); begin if xModify='1' then begin xModify :=''; Query_D.Edit; _SeqRefresh;//**自動編號 end; end; procedure TFABCD._SeqRefresh; var i,j:integer; xPoint : TBookMark; begin try i:=0; Query_D.DisableControls; Query_D.First; j:=StrToInt(xSeq_G); while Not Query_D.Eof do begin Query_D.Edit; if Query_D.FieldByName('Seq').AsString>=Format('%.3d',[Strtoint(xSeq_H)]) then begin if Query_D.FieldByName('Seq').AsString=Format('%.3d',[Strtoint(xSeq_H)]) then begin i:=i 1; if i> 1 then begin Query_D.Next; Continue; end; end; inc(j); Query_D.FieldByName('Seq').AsString := Format('%.3d',[j]); Query_D.Post; end; Query_D.Next; end; finally Query_D.EnableControls; end; end; procedure TFABCD.DBGrid_DKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState); begin if Key=VK_Insert then xDBGridKey:='Insert'; end; [/code]
------
http://blog.bestlong.idv.tw/ http://www.bestlong.idv.tw/ http://delphi-ktop.bestlong.idv.tw/
編輯記錄
bestlong 重新編輯於 2011-08-03 23:33:48, 註解 無‧
|
本站聲明 |
1. 本論壇為無營利行為之開放平台,所有文章都是由網友自行張貼,如牽涉到法律糾紛一切與本站無關。 2. 假如網友發表之內容涉及侵權,而損及您的利益,請立即通知版主刪除。 3. 請勿批評中華民國元首及政府或批評各政黨,是藍是綠本站無權干涉,但這裡不是政治性論壇! |