0

I have a hierarchy structure consisting of A,B,C,D. Each entity has a one-to-many relationship to its child (A -> 1:N -> B -> 1:N -> C -> 1:N -> D).
I have another entity, lets call it X, which can be linked to one of those hierarchical entities using LevelID and LevelTypeID fields (LevelID is a foreign key to A,B,C or D and LevelTypeID is a foreign key to a look up table which contains the names of A,B,C and D)

Based on supplied LevelID and LevelTypeID, I need a query which can give me the current hierarchical entity and any higher parent level entities.

The following is some sample data in the 4 tables

   A
         ID       
         --
         1       
   B
         ID       A_ID
         ----     -----     
         10       1
   C
         ID       B_ID
         ----     -----
         100      10
   D
         ID       C_ID
         -----    -----
         1000     100
         1001     100

Using LevelId = 100, LevelTypeId = 3 (C), query should return:

   LevelTypeId    LevelId
   -----------    -------
   3               100
   2               10
   1               1

Using LevelId = 1000, LevelTypeId = 4 (D), query should return:

   LevelTypeId    LevelId
   -----------    -------
   4               1000
   3               100
   2               10
   1               1

I was using query below, but I am not getting the correct results, especially when I filter on LevelId = 100, LevelTypeId = 3

select LevelTypeId, LevelId
from
   (    select  
            a.ID as [1], 
            b.ID as [2],
            c.ID as [3], 
            d.ID as [4]
        from A a
        left join B b on a.ID = b.A_ID
        left join C c on b.ID = c.B_ID
        left join D d on c.ID = d.C_ID
        where 
            (@levelTypeId = 4 and D.ID = @levelId)
            or
            (@levelTypeId = 3 and C.ID = @levelId)
            or
            (@levelTypeId = 2 and B.ID = @levelId)
            or
            (@levelTypeId = 1 and A.ID = @levelId)

   ) p   
unpivot
   (LevelId FOR LevelTypeId IN ([1], [2], [3], [4])) AS unpvt

Can anyone help me with this query?

12
  • I'm really confused by your schema here. All you give us is ID, Parent, and your letter classes. How are these related to levelid and leveltypeyid? It might help if instead of using the literal names in your schema, you use more descriptive functional names here.
    – David Marx
    Commented Jun 7, 2013 at 17:59
  • Its in the second paragraph: "LevelID is a foreign key to A,B,C or D and LevelTypeID is a foreign key to a look up table which contains the names of A,B,C and D" Commented Jun 7, 2013 at 18:01
  • Why don't you walk me through your first example, because it's really unclear to me why that's the expected result of the proposed query. This is your data and it makes sense to you, but it's not being explained super clearly from my perspective. For example, where does LevelId=101 fit into this at all? It doesn't appear in either column of the table we're given.
    – David Marx
    Commented Jun 7, 2013 at 18:03
  • Sorry that was a typo Commented Jun 7, 2013 at 18:04
  • @BlueChameleon . . . Are the LevelIds as nicely structured as in the question? That is, is level <n+1> simply level <n> + some digit? Commented Jun 7, 2013 at 18:05

1 Answer 1

1

Your existing query is returning all levels in the join, because the only level selection is occurring in the where clause - if any level matches the criteria, then all levels are selected. Instead, try:

select LevelTypeId, LevelId
from
   (    select  
            a.ID as [1], 
            b.ID as [2],
            c.ID as [3], 
            d.ID as [4]
        from A a
        left join B b on a.ID = b.A_ID and @levelTypeId >= 2
        left join C c on b.ID = c.B_ID and @levelTypeId >= 3
        left join D d on c.ID = d.C_ID and @levelTypeId >= 4
        where 
            (@levelTypeId = 4 and D.ID = @levelId)
            or
            (@levelTypeId = 3 and C.ID = @levelId)
            or
            (@levelTypeId = 2 and B.ID = @levelId)
            or
            (@levelTypeId = 1 and A.ID = @levelId)

   ) p   
unpivot
   (LevelId FOR LevelTypeId IN ([1], [2], [3], [4])) AS unpvt

SQLFiddle here.

0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.