2009-04-18 23 views
18

私はjobテーブルAccessで再帰クエリを作成することはできますか?

Id 
ParentID 
jobName 
jobStatus 

ルートのParentIDは0

である、それはAccessで与えられたjobのルートを検索するクエリを作成することは可能ですか? データベースはリンクテーブルのないMDBです。 Accessバージョンは2003年です。jobは、いくつかのレベルの深いグランド子供になることができます。

+0

"仕事がいくつかの壮大な子レベルにある"と言ったり、いくつかのダミーデータを貼り付けたりするときはもっと正確に記述してください。 –

答えて

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-99」と区別するために、「ISO/ANSI標準SQL」に接尾辞年を付ける必要がありますか? –

4

再帰的にクエリを実行することはできません。

任意の数の左ジョインを行うこともできますが、ジョインしたレベルだけ上げることができます。

Celko's "Nested Set Model"を使用すると、すべての親を取得できます。これにより、挿入と更新がより複雑になるように、テーブル構造を変更する必要があります。

+0

再帰的にクエリを実行することはできません。 - >アクセス03には、とにかく、他の多くのクエリlangsにすることができます – Peter

+0

はい、 "あなた" OPを使用している人は、再帰的にクエリすることはできません。 – tpdi

+0

ネストされたセットはCelkoによって一般化されましたが、このメソッドはMichael J. Kamfonas(http://en.wikipedia.org/wiki/Joe_Celko)に入金されます。 – onedaywhen

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歳であることを認識していますが、誰もが不可能なことを言うときに私は答えなければなりません)。

+11

私はあなたの投稿に拍手を送っていますが、元の質問は実際にはVBAなしでは不可能な質問に対する答えを実際に制限しています。 「クエリで」を「カスタムVBA関数に依存しない」と解釈するのが公正であるかどうかは別の問題です。同じ問題を抱えている他の人たちが純粋なSQLの答えではないという脅威がないので、元のポスターが探していたものではないにしても、あなたのソリューションをここに置くことは良いことだと思います。 –

+1

これは、呼び出されるたびに新しいレコードセットを開くことを意味するため、非常に非効率的です。私は最低でも、モジュールレベルの変数でレコードセットを保持するか、レコードセット全体をメモリ内のモジュールレベルのScripting.Dictionaryにロードすることをお勧めします。これは、[this](http:// stackoverflow)のような高速アクセスを可能にします。 com/a/32161506)。 @ David-W-Fenton –

1

OKこれが本当のところです。最初に、あなたの質問のターゲットオーディエンスは何ですか?フォーム?報告する?関数/ proc?

フォーム:更新が必要ですか?それはうまく動作して不器用な間にtreeviewコントロールを使用してください。 Report:openイベントでパラメータフォームを使用して "Boss Job"レベルを設定し、次にVBAの再帰を処理し、データのレコードセットを希望の順に入力します。このレコードセットにレポートレコードセットを設定し、レポートを処理します。 機能/手順:上記のレポートで説明したデータ読み込みとほぼ同じです。コードを使用して、必要な「ツリーウォーキング」を処理し、必要に応じて結果セットをレコードセットおよびプロセスに必要な順序で格納します。

+2

どのようなTreeviewコントロールですか?私が知っているAccessのどのバージョンでも利用可能なネイティブTreeviewはありません。 –

+0

これは既存の回答にはうってつけかもしれませんが、仕事が必要です。たとえば、「OK」を削除すると、実際の取引が表示されます。オプションを箇条書きまたはパラに分割します。それぞれを展開して明確にする。 –

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 

と同じコンテキスト内の別の便利な機能があります。 "ChildHasParent"は、子が任意の入れ子レベルの指定されたParentIDと一致する場合にtrueを返します。

関連する問題