MySQL或VBA迭代函数查找相互关联的记录

时间:2011-11-29 22:58:40

标签: mysql ms-access

我正在使用带有MySQL数据库的MS Access。一个表有记录,代表'文件':

Table: doc
Primary Key: doc_id

这些记录可以通过链接表链接在一起:

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

因此,记录可以链接在一起,例如链接到Doc B的Doc A,它与Doc C等相关联,而且Doc A可以链接到任意数量的其他文档。

实际上,相互关联文件的“家庭”不会超过20条记录。

我正在寻找一个有效的MySQL proc或VBA函数 - 或查询 - 来查找一个指定记录的'family'的所有成员。

欢迎任何建议!

3 个答案:

答案 0 :(得分: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)。

答案 1 :(得分:1)

因此,链接表提供了一个自我加入doc,你绝对需要一个doc才能:

  1. 链接到自己
  2. ......多次喜欢
  3. 链接到其他文档
  4. ......多次
  5. 由相同的其他文档单独链接
  6. ......多次
  7. 存储有关链接的信息
  8. 所以你的链接表可能有10个单独的链接1-1,1-1,1-1,1-2,2-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往返服务器。

答案 2 :(得分:1)

前段时间我遇到过类似的问题。我没有在文档之间创建链接,而是使用了包含族的单独表格:

Table: LinkTable
PK: LinkId, DocumentID
FK: DocumentID

每次创建新系列时,都不会使用成对的文档ID,而是引入新的LinkId。

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 }

检索族更容易,但是需要更复杂的逻辑来插入和删除家庭文件。