2011-11-29 67 views
0

我正在使用MS Access和MySQL數據庫。一個表具有表示「的文件」記錄:MySQL或VBA迭代函數查找相關記錄

Table: doc 
Primary Key: doc_id 

這些記錄可以經由鏈路表被鏈接在一起:

Table: link 
Primary Key: link_id 
Foreign Key: doc_id_A 
Foreign Key: doc_id_B 

因此,記錄可在鏈中被鏈接,例如文件甲鏈接到與文檔C等鏈接的文檔B,以及文檔A可以鏈接到任意數量的其他文檔。

實際上,相關文件的「家族」不會超過20條記錄。

我正在尋找一個高效的MySQL proc或VBA函數 - 或查詢 - 查找一個指定記錄的「家族」的所有成員。

任何建議將是最受歡迎的!

+0

這是否有用? http://explainextended.com/2009/03/17/hierarchical-queries-in-mysql/ – Fionnuala

+0

嗨Remou,謝謝你的隊友,明天再去探索你的鏈接。 – maxhugen

+0

嗨Remou,謝謝你的伴侶(我們之前聊過並解決過的事情),明天再去探索你的鏈接。 雖然快速瀏覽一下,但它看起來只能處理父母/子女關係。在我的「連接」表中,我們想要的「家人」文檔可以是父母或孩子。這是一個未定義的層次結構(即根本沒有層次結構,記錄只是鏈接在一起)。 我目前有一個工會聯合,需要六個查詢才能達到2級深。作爲澳大利亞人,我樂意爲你提供一兩塊(啤酒)來幫助我。 – maxhugen

回答

1

所以鏈接的表格給出了自加盟文檔,你絕對需要一個文檔能夠:

  1. 鏈接本身
  2. ...很多次,因爲它喜歡
  3. 鏈接到另一個文檔
  4. ...多次
  5. 被同其他文檔分別連接到
  6. ...多次
  7. 關於鏈接存儲信息

所以你的鏈接表可能有10個單獨的鏈接1-1,1-1,1-1,1-2,1-2,1-2,2-1, 2-1,2-1,2-2等,只有2個文件在'家庭'中。


當你看這個名單,你可能會認爲你不需要他們大多我希望,在解決方案中很多低效率可能會從這種不必要的靈活性到來。我最喜歡的建議是從嚴格的層次開始,並從那裏開始建設。

但無論如何,這是我的答案,它在Access-2010和本地表中進行了測試和工作。 ADODB應該和鏈接表一樣工作。

Option Compare Database 
Option Explicit 
Const MaxInFamily = 30 

'Requires a reference to "Microsoft ActiveX Data Objects 2.x Library" (VBA Menu: Tools, references) 

Function GetFamily(id As Long) As Long() 
Dim Found(MaxInFamily) As Long 
Dim MaxFound As Integer 
Dim CurrentSearch As Integer 
Dim Sql As String 
Dim rs As New ADODB.Recordset 

    Found(1) = id 
    MaxFound = 1 

    For CurrentSearch = 1 To MaxInFamily 

     If CurrentSearch > MaxFound Then Exit For 

     Sql = "SELECT doc_id_2 as NewID FROM link WHERE doc_id_1 = " & Found(CurrentSearch) _ 
       & " AND doc_id_2 NOT IN (" & ArrayToCsv(Found, MaxFound) & ")" _ 
       & " UNION " _ 
       & " SELECT doc_id_1 FROM link WHERE doc_id_2 = " & Found(CurrentSearch) _ 
       & " AND doc_id_1 NOT IN (" & ArrayToCsv(Found, MaxFound) & ")" 

     rs.Open Sql, CurrentProject.Connection 

     Do While Not rs.EOF 
      MaxFound = MaxFound + 1 
      Found(MaxFound) = rs("NewID").Value 
      rs.MoveNext 
     Loop 

     rs.Close 

    Next CurrentSearch 

    GetFamily = Found 

End Function 

Function ArrayToCsv(SourceArray() As Long, ItemCount As Integer) As String 
Dim Csv As String 
Dim ArrayIndex As Integer 

    For ArrayIndex = 1 To ItemCount 
     Csv = Csv & SourceArray(ArrayIndex) 
     If ArrayIndex < ItemCount Then Csv = Csv & ", " 
    Next ArrayIndex 

    ArrayToCsv = Csv 

End Function 

重複的結果和查詢通過排除已經發現在服務器項目避免,併爲紐帶是單向的,我使用的UNION查詢一次朝兩邊看。最多它會做MaxInFamily往返服務器。

+0

謝謝webturner。我相信你對工會的加入是正確的 - 因爲你表達得比我更好,鏈接是單向的。但是,您的要點(1)和(2)不適用,因爲文檔無法在邏輯上鍊接到自身。現在,這個數組當然是我從未想過的東西,所以我會嘗試一些代碼。 – maxhugen

+0

Webturner,你的功能非常棒。我更改GetFamily返回一個字符串,並將結果更改爲 – maxhugen

+0

GetFamily = ArrayToCsv(Found,MaxFound) 不幸的是,該函數不直接在查詢中工作,例如: SELECT * FROM doc WHERE doc_id IN(GetFamily([some_doc_id ])) 有沒有我在這裏失蹤的東西,還是我需要通過VBA手動設置表單/報告的記錄源? – maxhugen

1

不幸的是,在給定MySQL表不支持遞歸查詢這樣的表結構的情況下,MySQL不能完成。我建議在Mysql recursion?中探索答案 - 關於如何在MySQL中存儲數據以便能夠編寫這樣的查詢,有一些建議。

您還有其他三個選項:

如果你知道最大。這些家庭的深度,並不是很大,你仍然可以用mySQL來實現它。對於3個層次的深度,它應該是這樣的:

SELECT A.doc_id_a as a, B.doc_id_a a_child, C.doc_id_a as a_sub_child 
FROM links as A, links as B, links as C 
WHERE A.doc_id_a = your_doc_id AND 
     A.doc_id_b = B.doc_id_a AND 
     B.doc_id_b = C.doc_id_a 

按照同樣的邏輯,你可以根據需要添加儘可能多的層。唯一的問題是 - 您需要從所有列中獲取結果並找到唯一值(如果關係不是始終爲1-1,則可以有多行)。

第二種選擇是在VBA中執行此操作。我不知道足夠提供的代碼,但實際上它可能看起來像這樣(遞歸的方法):

family = array(); 
family = getFamily('your_doc_id', family); 

function getFamily(id) { 
    children = DB->getColumn('SELECT doc_id_b FROM links WHERE doc_id_a = ?', id); 
    if (empty(children)) return family; 
    else { 
    foreach (children as child) { 
     family[] = getFamily(child); 
    } 
    } 
} 

最後,您可以切換到PostgreSQL,支持遞歸查詢:) (http://www.postgresql.org/docs/8.4/static/queries-with.html)。

+0

感謝Aurimas,我會檢查你的建議鏈接,並嘗試你的建議。讓你知道我是怎麼走的! – maxhugen

1

前段時間我有類似的問題。而不是創建文檔之間的鏈接中我使用含有家屬一個單獨的表:

Table: LinkTable 
PK: LinkId, DocumentID 
FK: DocumentID 

而不必對文檔ID的,每次創建一個新的家庭,便增加了一個新的鏈路ID。

LinkId | DocumentID 

1  | 7 
1  | 9 
1  | 13 
2  | 4 
2  | 22 
2  | 23 
2  | 30 
3  | 6 
3  | 80 

這裏你有三個家庭與文檔ID:

{ 7, 9, 13 }, 
{ 4, 22, 23, 30 }, 
{ 6, 80 } 

這是比較容易獲取的家庭,但是它需要插入和刪除文件,並從家庭稍微更復雜的邏輯。

+0

是的,可能會變得有點複雜,例如,如果您之後鏈接了DocID 9和23,那麼您的家人ID就會出現問題。 – maxhugen

+0

這就是我的意思是「更復雜的邏輯」。我的實現是針對Oracle的,並用於不同的Access應用程序。爲了確保鏈接表的完整性,我創建了用於插入和刪除條目的存儲過程,而不是直接訪問鏈接表。例如,如果從鏈接表中刪除一個文檔,那麼留在家庭中的單個文檔也將不得不被刪除,因爲它不再鏈接到任何其他文檔。 –