Store multidimensional array in database: relational or multidimensional?

后端 未结 6 1726
栀梦
栀梦 2021-02-14 02:14

I have read numerous posts along the lines of multidimensional to single dimension, multidimensional database, and so on, but none of the answers helped. I did

6条回答
  •  有刺的猬
    2021-02-14 02:21

    I have two words for you... "RANGE KEYS"

    You may find this technique to be incredibly powerful and flexible. You'll be able to navigate your hierarchies with ease, and support variable depth aggregation without the need for recursion.

    In the demonstration below, we'll build the hierarchy via a recursive CTE. For larger hierarchies 150K+, I'm willing to share a much faster build in needed.

    Since your hierarchies are slow moving (like mine), I tend to store them in a normalized structure and rebuild as necessary.

    How about some actual code?

    Declare @YourTable table (ID varchar(25),Pt varchar(25))
    Insert into @YourTable values 
    ('A'   ,NULL),
    ('AA'  ,'A'),
    ('AAA' ,'AA'),
    ('AAC' ,'AA'),
    ('AB'  ,'A'),
    ('AE'  ,'A'),
    ('AEA' ,'AE'),
    ('AEE' ,'AE'),
    ('AEEB','AEE')
    
    
    Declare @Top  varchar(25) = null     --<<  Sets top of Hier Try 'AEE'
    Declare @Nest varchar(25) ='|-----'  --<<  Optional: Added for readability
    
    IF OBJECT_ID('TestHier') IS NOT NULL 
    Begin
        Drop Table TestHier
    End
    
    ;with cteHB as (
          Select Seq  = cast(1000+Row_Number() over (Order by ID) as varchar(500))
                ,ID
                ,Pt
                ,Lvl=1
                ,Title = ID
          From   @YourTable 
          Where  IsNull(@Top,'TOP') = case when @Top is null then isnull(Pt,'TOP') else ID end
          Union  All
          Select cast(concat(cteHB.Seq,'.',1000+Row_Number() over (Order by cteCD.ID)) as varchar(500))
                ,cteCD.ID
                ,cteCD.Pt
                ,cteHB.Lvl+1
                ,cteCD.ID
          From   @YourTable cteCD 
          Join   cteHB on cteCD.Pt = cteHB.ID)
         ,cteR1 as (Select Seq,ID,R1=Row_Number() over (Order By Seq) From cteHB)
         ,cteR2 as (Select A.Seq,A.ID,R2=Max(B.R1) From cteR1 A Join cteR1 B on (B.Seq like A.Seq+'%') Group By A.Seq,A.ID )
    Select B.R1  
          ,C.R2
          ,A.ID
          ,A.Pt
          ,A.Lvl
          ,Title = Replicate(@Nest,A.Lvl-1) + A.Title
     Into dbo.TestHier
     From cteHB A
     Join cteR1 B on A.ID=B.ID
     Join cteR2 C on A.ID=C.ID
     Order By B.R1
    

    Show The Entire Hier I added the Title and Nesting for readability

    Select * from TestHier Order By R1
    

    Just to state the obvious, the Range Keys are R1 and R2. You may also notice that R1 maintains the presentation sequence. Leaf nodes are where R1=R2 and Parents or rollups define the span of ownership.


    To Show All Descendants

    Declare @GetChildrenOf varchar(25) = 'AE'
    Select A.*
      From TestHier A
      Join TestHier B on B.ID=@GetChildrenOf and A.R1 Between B.R1 and B.R2
      Order By R1
    


    To Show Path

    Declare @GetParentsOf varchar(25) = 'AEEB'
    Select A.*
      From TestHier A
      Join TestHier B on B.ID=@GetParentsOf and B.R1 Between A.R1 and A.R2
      Order By R1
    

    Clearly these are rather simple illustrations. Over time, I have created a series of helper functions, both Scalar and Table Value Functions. I should also state that you should NEVER hard code range key in your work because they will change.

    In Summary

    If you have a point (or even a series of points), you'll have its range and therefore you'll immediately know where it resides and what rolls into it.

提交回复
热议问题