2012-07-27 66 views
0

我想我錯過了關於使用SQL語句和(Delphi的ADO)查詢組件和/或在(Access 2003)數據庫中的字段之間設置關係的基礎知識。每當我想刪除,更新等任何比SQL.Text =「SELECT something from aTable」更復雜的東西時,我會收到錯誤消息。如何刪除,更新等由Delphi ADO查詢生成的表格?

例如,我在表之間創建了一個簡單的多對多關係,稱爲Outline和Reference。結或連接表被稱爲注:

Outline 
    OutlineID (PK) 
    etc. 

Reference 
    RefID (PK) 
    etc. 

Note 
    NoteID (PK) 
    OutlineID 
    RefID 
    NoteText 

我強制在Access中的聯接引用完整性,但級聯刪除或更新不勾選複選框。同時,在Delphi中我Query.SQL.Text是

SELECT Note.NoteID, Outline.OutlineID, Ref.RefID, Note.NoteText, Ref.Citation, Outline.OutlineText 
FROM (Note LEFT JOIN Outline ON Outline.OutlineID=Note.OutlineID) 
LEFT JOIN Ref on Ref.RefID=Note.RefID; 

起初我離開了引用在SELECT語句鍵,產生「不足鍵列信息」的錯誤,當我試圖從導致刪除記錄表。我認爲我明白:你必須選擇數據庫將需要執行的任何操作所需的所有字段。它不能刪除,更新等加入的字段,如果它不知道什麼加入了什麼。 (這是對嗎?)

那麼,我該如何從這個查詢中刪除記錄?換句話說,我想(1)顯示一個顯示NoteText,Citation和OutlineText的網格,(2)從網格中選擇一條記錄,(3)在DBNavigator上點擊Delete按鈕,(4)刪除註釋表中與所選記錄具有相同NoteID和NoteText的記錄。

+0

您是否在使用TADOQuery,以及「從此查詢中刪除記錄」是什麼意思? – 2012-07-27 16:46:38

+0

是的,TADOQuery。通過「刪除記錄......」我可以看到你的困惑;感謝您指出了這一點。看我的編輯。 – 2012-07-27 16:59:31

+0

當我使用TADOQuery加入sql&顯示在dbgrid中時,我沒有使用查詢本身來刪除記錄。我使用帶參數的TADOCommand來執行刪除操作。我使用dbgrid.datasource.dataset.fieldbyname('param')。asString(或任何字段類型)的值爲參數賦值。之後,我執行命令並刷新網格。 – Hendra 2012-07-28 04:16:09

回答

2

James L和Hendra都提供瞭如何做你想做的事情的本質。以下是實現它的一種方式。

procedure TForm1.ADOQuery1BeforeDelete(DataSet: TDataSet); 
var 
    SQL : string; 
begin 
    SQL := 'DELETE FROM [Note] WHERE NoteID='+ 
    DataSet.FieldByName('NoteID').AsString; 
    ADOConnection1.Execute(SQL); 
    TADOQuery(DataSet).ReQuery; 
    Abort; 
end; 

這將允許TADOQuery.Delete正常工作。中止對於防止TADOQuery在刪除記錄後嘗試刪除記錄是必要的。主要缺點是TADOQuery.ReQuery不保留光標位置,即當前記錄將成爲第一條記錄。

更新:

下試圖恢復光標。我不喜歡第二個Requery,但似乎有必要在嘗試恢復無效書籤(由於刪除最後一條記錄)後恢復DataSet。這與我有限的測試一起工作。

procedure TForm1.ADOQuery1BeforeDelete(DataSet: TDataSet); 
var 
    SQL : string; 
    bm : TBookmarkStr; 
begin 
    SQL := 'DELETE FROM [Note] WHERE NoteID='+ 
    DataSet.FieldByName('NoteID').AsString; 
    bm := Dataset.BookMark; 
    ADOConnection1.Execute(SQL); 
    TADOQuery(DataSet).ReQuery; 
    try 
    Dataset.BookMark := bm; 
    except 
    TADOQuery(DataSet).Requery; 
    DataSet.Last; 
    end; 
    Abort; 
end; 
+0

關於保存光標位置,我沒有試過這個,但是這個工作?如何獲取當前記錄的書籤之前刪除,做上面的代碼,轉到保存的書籤(將去下一個記錄),然後釋放書籤和中止?我不知道訪問數據庫是否是單向的。 – Hendra 2012-07-29 03:00:00

+0

@ Hendrea。您關於捕獲當前記錄的書籤並在刪除後恢復它的想法直到它被刪除的最後一條記錄。使用D2007,我無法避免TBookmark的異常,即使在TADOQuery.BookValid中嘗試..除外。我有TBookmarkStr工作,但不喜歡使其工作的一些必要步驟(在我的有限測試中)。我已經用代碼更新了我的答案。 至於你評論關於訪問是單向的,這是TADQuery而不是數據庫的功能。 – crefird 2012-07-29 18:48:03

+0

我想到了避免第二次詢問。如果它不是最後一個記錄,那麼只能進入書籤?因此,在執行上面的sql之前,請先檢查最後一條記錄(即dataset.next;如果dataset.eof然後設置isLastRecord = true; dataset.prior;)。重新查詢後,替換嘗試...除非用isLastRecord然後Dataset.Bookmark:= bm else Dataset.last;所以,第二個查詢是不需要的。 – Hendra 2012-07-30 05:31:16

0

如果您使用的是TADOTable,那麼當您從TADOTable數據集中刪除它們時,這些組件會處理數據庫中的刪除操作。但是,由於您正在使用連接多個表的TADOQuery,因此您需要以不同方式處理數據庫刪除。

當您創建記錄要刪除數據庫網格中的當前記錄時,它會將TADOQuery的光標滾動到其數據集中的該行。然後您可以使用TADOQuery.Delete刪除當前記錄。如果您爲TADOQuery.BeforeDelete事件編寫代碼,則可以在本地刪除記錄之前捕獲記錄中的標識字段,並使用另一個TADOQueryTADOCommand組件,您可以創建並執行SQL以從數據庫中刪除記錄。

由於從數據庫中刪除記錄的代碼位於BeforeDelete事件中,如果發生異常並且數據庫記錄未被刪除,本地刪除也將被取消,並且本地記錄不會被刪除 - - 並顯示錯誤(例如,'外鍵違規'...)。

+0

L - 我嘗試了你的建議,通過我已經使用的ADOConnection組件執行DELETE語句。我收到一個錯誤,指出無法找到行進行更新,該值自上次讀取後可能已更改。有趣的是,該記錄仍然被刪除 - 但其他表格中的記錄也是如此。 – 2012-07-27 18:12:15

+0

聽起來像原來的'TADOQuery'試圖從數據庫中刪除它,你手動刪除後。也許只是在'BeforeDelete'事件中做'TADOQuery.Delete'而不做任何事情就足夠了?我不經常使用ADO組件 - 如果查詢不太複雜,也許他們處理更新/刪除操作......也許'TADOQuery'正在刪除所有參與表中的記錄?如果你只是想刪除* 1 *記錄,你需要找到一種方法來關閉原來的'TADOQuery'的自動更新...並在'BeforeDelete'中手動處理... – 2012-07-27 18:20:00

相關問題