【问题标题】:SQL for MSACCESS how to implement character delimited data hierarchy?SQL for MS ACCESS 如何实现字符分隔的数据层次结构?
【发布时间】:2017-11-10 20:55:28
【问题描述】:

比如说,有一个扁平的顺序层次结构表,其中特殊字符“+”表示层次结构级别

hr_table
ID   FIELD1        My irrelevant comments
----------------
1    ASSETS        No pluses - it means level0 hierarchy
2    +ASSETS_01    Level1 hierarchy
3    ++345667654   Level2 hierarchy
4    ++563255512   Level2 hierarchy
5    ...

有没有办法使用 SQL 在 MSACCESS 中创建字段结构?我正在尝试按如下方式构建最终数据:

final_data_table
ID  LEVEL0     LEVEL1       LEVEL2    ...
-------------------------------------------
1   ASSETS     ASSETS_01    345667654
2   ASSETS     ASSETS_01    563255512

非常感谢任何/所有帮助!

【问题讨论】:

  • 可以有多少个级别,并且总是会有最多级别的行(即,如果是 3 个级别,是否总是有 3 行来填充您的表格)?我知道您可以使用 VBA 在 Access 中处理,并且可以使用 Excel 重新格式化为扁平行。
  • 什么标准决定了那些 Level2 数字与 ASSETS_01 一起而不是 ASSETS_02?
  • FIELD1 成员将需要检查以计算“+”的最大出现次数。这将确定最大级别数。但这几乎是预先确定的。比如说,最大级别数是 5(例如),它不会改变。
  • 因为“++345667654”依次跟随更高层次的成员“+ASSETS_01”...如果它出现在表格的后面,跟随假设的成员“+ASSETS_02”,那么正确的 LEVEL1 层次结构将是资产_02。基本上,顺序完整性将“子”链接到最近列出的 LEVEL 层次结构描述符......
  • 我也很怀疑。然后我同意@WayneG.Dunn,使用 VBA 循环结构读取记录集对象并将记录写入“临时”表(表是永久的,记录是临时的)。并且这假定 ID 值将始终增加并且可以依赖于正确排序记录。

标签: sql database ms-access data-structures


【解决方案1】:

好奇心战胜了我,所以我探索了查询方法。我求助于使用域聚合函数。请注意,域聚合函数在处理大型数据集时可能会执行缓慢。但是,请考虑:

查询1:

SELECT hr_table.ID, IIf([Field1] Like "+*",Left([Field1],InStrRev([Field1],"+")),0) AS Prefix, IIf([Field1] Like "+*",Null,[Field1]) AS Asset1, IIf(InStrRev([Field1],"+")=1,Mid([Field1],2),Null) AS Asset2, IIf([Field1] Like "++*",Mid([Field1],InStrRev([Field1],"+")+1),Null) AS Data
FROM hr_table;

查询2:

SELECT Query1.ID, Query1.Prefix, DMax("Asset1","Query1","ID<=" & [ID]) AS A1, DMax("Asset2","Query1","ID<=" & [ID]) AS A2, Query1.Data
FROM Query1
WHERE ((Not (Query1.Data) Is Null));

查询3:

SELECT Query2.Prefix, Query2.A1, Query2.A2, Query2.Data, DCount("*","Query2","A1='" & [A1] & "' AND A2='" & [A2] & "' AND Prefix = '" & [Prefix] & "' AND ID<=" & [ID]) AS GrpSeq
FROM Query2;

查询4:

TRANSFORM Max(Query3.Data) AS MaxOfData
SELECT Query3.A1, Query3.A2, Query3.GrpSeq
FROM Query3
GROUP BY Query3.A1, Query3.A2, Query3.GrpSeq
PIVOT Query3.Prefix;

我绝对不确定 Level3 及以上的治疗方法。可能是 VBA 将是唯一的解决方法。

【讨论】:

    【解决方案2】:

    以下代码已经过测试,可以与您提到的数据结构一起使用。它目前设置为最多处理 10 个级别,但可以轻松更改。棘手的部分是不要写出记录,直到您拥有该 ONE 行的所有级别(新行以不同的 level1 值开始,或者提供了多个 level-n 值时)。最后一行写在输入的 eof 之后。

    Option Compare Database
    Option Explicit
    
    Function Parse_Fields()
    Dim dbs As DAO.Database
    Dim rsIN    As DAO.recordSet
    Dim rsOUT   As DAO.recordSet
    Dim i       As Integer
    Dim iPlus   As Integer
    Dim aLevels(10)
    Dim bAdding As Boolean
    
        Set dbs = CurrentDb
        Set rsIN = dbs.OpenRecordset("hr_table")
        Set rsOUT = dbs.OpenRecordset("final_data_table")
        bAdding = False
    
        Do While Not rsIN.EOF
            'Debug.Print "Input: " & rsIN!field1
            If left(rsIN!field1, 1) <> "+" Then
                ' Check if not first time thru... if not, write prior levels..
                If bAdding = True Then
                    rsOUT.Update
                End If
                iPlus = 0
                rsOUT.AddNew
                rsOUT!Level0 = rsIN!field1
                bAdding = True
                ' Don't issue the .Update yet! Wait until another Level0 or EOF.
            Else
                For iPlus = 1 To 10         ' Change code if more than ten levels
                    If Mid(rsIN!field1, iPlus, 1) <> "+" Then Exit For
                Next iPlus
    
                ' Check if same level as previous!  If so, do NOT overlay!
                If Not IsNull(rsOUT.Fields(iPlus)) Then
                    For i = 1 To iPlus - 1      ' Save the proper levels for the new record.
                        aLevels(i) = rsOUT.Fields(i)
                    Next i
                    rsOUT.Update                ' Need to write out record.
                    rsOUT.AddNew
                    For i = 1 To iPlus          ' Populate the new record with prior levels
                         rsOUT.Fields(i) = aLevels(i)
                    Next i
                    rsOUT.Fields(iPlus) = Mid(rsIN!field1, iPlus)       ' Add the new level
                Else
                    rsOUT.Fields(iPlus) = Mid(rsIN!field1, iPlus)
                End If
            End If
            rsIN.MoveNext               ' Get next input
        Loop
    
        ' Need to write out the final record we have beenbuilding!
        rsOUT.Update
    
        rsIN.Close
        rsOUT.Close
        Set rsIN = Nothing
        Set rsOUT = Nothing
        Set dbs = Nothing
        Debug.Print "FINISHED!!"
    
    End Function
    

    【讨论】:

      猜你喜欢
      • 2010-12-26
      • 1970-01-01
      • 1970-01-01
      • 2018-10-30
      • 2011-08-27
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多