我正在使用带有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'的所有成员。
欢迎任何建议!
答案 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才能:
所以你的链接表可能有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 }
检索族更容易,但是需要更复杂的逻辑来插入和删除家庭文件。