2009-04-18 110 views
18

我有一個job是否可以在Access中創建遞歸查詢?

Id 
ParentID 
jobName 
jobStatus 

根PARENTID爲0

是否有可能在Access中創建一個查詢,以找到一個給定job根? 數據庫是沒有鏈接表的MDB。 Access版本是2003年。一個job可以是深層次的幾個級別的大孩子。

+0

當你說「工作可以在幾個大的孩子級別」或者粘貼一些虛擬數據時,請更精確一些。 – 2009-04-18 06:32:46

回答

8

不,它不是。在SServer 2005之後的SQL Server中支持遞歸查詢,但在Access中不支持。

如果你事先知道槓桿的數量,你可以寫一個qry,但它不會是一個遞歸的。

在SQL Server中,CTE(一個SQL擴展)用於那些:看http://blog.crowe.co.nz/archive/2007/09/06/Microsoft-SQL-Server-2005---CTE-Example-of-a-simple.aspx

常規的SQL但沒有遞歸性支持。

+0

@onedaywhen:是否/應該「ISO/ANSI標準SQL」具有後綴年,以幫助將其與「ISO/ANSI標準SQL-99」區分開來? – 2015-04-08 17:30:31

4

你不能遞歸查詢。

您可以執行一些任意數量的左連接,但只能加入與連接數量相同的級別。

或者您可以使用Celko's "Nested Set Model"檢索所有父母。這將需要修改您的表結構,以便使插入和更新變得更加複雜。

+0

你不能遞歸查詢。 - >無法訪問03反正,在許多其他查詢語言中,您可以 – Peter 2009-04-18 08:54:30

+0

是的,「您」使用Access的OP的用戶不能遞歸查詢。 – tpdi 2009-04-18 21:14:40

+0

雖然嵌套組被celko推廣,但該方法被記入Michael J. Kamfonas(http://en.wikipedia.org/wiki/Joe_Celko)。 – onedaywhen 2009-04-20 08:33:51

24

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 

您可以使用查詢生成器或函數名在查詢字段變量只是打字調用從查詢這個遞歸函數。

它會產生根。

(我承認OP現在已經一歲了,但我不得不在每個人都說不可能的時候回答)。

1

好吧,這是真正的交易。首先,您的查詢的目標受衆是什麼?表單?報告?功能的/ proc?

窗體:需要更新?使用樹視圖控件雖然笨拙,它將很好地工作。 報告:在打開的事件中,使用參數表單來設置「Boss作業」級別,然後處理vba中的遞歸併使用數據以所需的順序填充記錄集。將報告記錄集設置爲此填充的記錄集並處理報告。 函數/過程:與上面報告中描述的數據加載幾乎相同。通過代碼,處理必要的「樹行走」,並將結果集按需要的順序存儲在記錄集和進程中。

2

這不能在Access中使用純SQL來完成,但有點VBA有很長的路要走。

添加到Microsoft腳本運行時參考(工具 - >引用...)。

這假設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 
0

Zev的貢獻給了我很大的啓發和學習。但是,需要對代碼進行一些編輯。請注意,我的表格被稱爲「tblTree」。

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