我有一个job
表
Id
ParentID
jobName
jobStatus
根节点的ParentID为0。
在Access中是否可以创建一个查询来找到给定工作的根节点? 该数据库是没有链接表的MDB格式,并且使用的Access版本是2003。工作可能有多层子孙。
在Access中,可以创建一个查询来查找给定作业的根源。不要忘记VBA函数的强大功能,您可以在VBA模块中创建一个递归函数,并将其结果用作查询中的输出字段。
示例:
Public Function JobRoot(Id As Long, ParentId As Long) As Long
If ParentId = 0 Then
JobRoot = Id
Exit Function
End If
Dim Rst As New ADODB.Recordset
Dim sql As String
sql = "SELECT Id, ParentID FROM JobTable WHERE Id = " & ParentId & ";"
Rst.Open sql, CurrentProject.Connection, adOpenKeyset, adLockReadOnly
If Rst.Fields("ParentID") = 0 Then
JobRoot = Rst.Fields("Id")
Else
JobRoot = JobRoot(Id, Rst.Fields("ParentID")) ' Recursive.
End If
Rst.Close
Set Rst = Nothing
End Function
您可以通过查询构建器调用这个递归函数,或者只需在查询字段中键入带有参数的函数名称即可。它将产生根节点。在Access中无法使用纯SQL完成此操作,但稍加VBA编程可以轻松解决。
请添加对Microsoft Scripting Runtime的引用(工具->引用...)。
假设ID是唯一的,并且不存在循环:例如A的父项是B,但B的父项是A。
Dim dict As Scripting.Dictionary
Function JobRoot(ID As Long) As Long
If dict Is Nothing Then
Set dict = New Scripting.Dictionary
Dim rs As DAO.Recordset
Set rs = CurrentDb.OpenRecordset("SELECT ID, ParentID FROM Job", dbOpenForwardOnly, dbReadOnly)
Do Until rs.EOF
dict(rs!ID) = rs!ParentID
rs.MoveNext
Loop
Set rs = Nothing
Dim key As Variant
For Each key In dict.Keys
Dim possibleRoot As Integer
possibleRoot = dict(key)
Do While dict(possibleRoot) <> 0
possibleRoot = dict(possibleRoot)
Loop
dict(key) = possibleRoot
Next
End If
JobRoot = dict(ID)
End Function
Sub Reset() 'This needs to be called to refresh the data
Set dict = Nothing
End Sub
好的,这是真正的内容。首先,你的查询面向的受众是什么?是表格吗?报告?函数/过程?
表格:需要更新?使用树视图控件,虽然有点繁琐,但会很好用。 报告:在打开事件中使用参数表单来设置“Boss Job”级别,然后在vba中处理递归并用数据按所需顺序填充记录集。将报表的记录集设置为这个填充的记录集并处理报表。 函数/过程:基本上与上述报告中描述的数据加载相同。通过代码处理必要的“树形遍历”并将结果集以所需顺序存储在记录集中,然后根据需要进行处理。
Public Sub RemoveChildKeys(MyKey)
' deletes passed key and removes all children and grandchildren ect etc of passed key recursively
Dim TheDB As DAO.Database
Dim TheTable As DAO.Recordset
Dim MySql As String
Set TheDB = CurrentDb
MySql = "Select * from TblIndex WHERE [Parent]=" & MyKey & ";"
Set TheTable = TheDB.OpenRecordset(MySql)
While Not TheTable.EOF
RemoveChildKeys (TheTable!Key) ' <---- Calls itself
TheTable.MoveNext
Wend
DoCmd.RunSQL "Delete * FROM TblIndex WHERE [Key]=" & MyKey ' delete in table
End Sub
Dim dict As Scripting.Dictionary
Function TreeRoot(ID As Long) As Long
If dict Is Nothing Then
Set dict = New Scripting.Dictionary ' Requires Microsoft Scripting Runtime
Dim rs As DAO.Recordset
Set rs = CurrentDb.OpenRecordset("tblTree", dbOpenForwardOnly, dbReadOnly)
Do Until rs.EOF
dict.Add (rs!ID), (rs!ParentID)
rs.MoveNext
Loop
Set rs = Nothing
End If
TreeRoot = ID
Do While dict(TreeRoot) <> 0 ' Note: short version for dict.item(TreeRoot)
TreeRoot = dict(TreeRoot)
Loop
End Function
同样的上下文中还有一个有用的函数。如果孩子节点与任何嵌套层次中提供的ParentID匹配,则“ChildHasParent”返回true。
Function ChildHasParent(ID As Long, ParentID As Long) As Boolean
If dict Is Nothing Then
Set dict = New Scripting.Dictionary ' Requires Microsoft Scripting Runtime
Dim rs As DAO.Recordset
Set rs = CurrentDb.OpenRecordset("tblTree", dbOpenForwardOnly, dbReadOnly)
Do Until rs.EOF
dict.Add (rs!ID), (rs!ParentID)
rs.MoveNext
Loop
Set rs = Nothing
End If
ChildHasParent = False
Do While dict(ID) <> 0 ' Note: short version for dict.item(TreeRoot)
ID = dict(ID)
If ID = ParentID Then
ChildHasParent = True
Exit Do
End If
Loop
End Function