Take the 2-minute tour ×
Stack Overflow is a question and answer site for professional and enthusiast programmers. It's 100% free, no registration required.

Say you have a tree of data

A
|
+----B
|    |
|    +----C
|
+----D

to represent this in an oracle database we might have

create table mydata (id number(10), parent_id number(10), name varchar2(10))

and use a hierarchical query to traverse the tree.

What is the best way to define a sparse property set, such that child nodes inherit property values from the closest parent node?

In the above example, say we want to add owner and colour to the tree - how can the hierarchical query be modified to provide the inherited values?

My first thought was to create a new table

create table myproperties (id number(10), owner varchar2(30), colour varchar2(30));

We'd want the values in this table to be sparse as well - so a row in myproperties might specify 'owner' but leave 'colour' null. A given node in mydata would have a merged set of all non-null parent properties.

Then do an analytic query to fill in the gaps:

select * from (
    select
        id, groupid, parent_id, 
        last_value(owner ignore nulls) over (partition by groupid order by l desc) owner,
        last_value(colour ignore nulls) over (partition by groupid order by l desc) colour
    from
        (
            -- query from leaf to root
            select
                id, connect_by_root id groupid, level l, p.owner, p.colour
            from
                mydata d left outer join myproperties p on p.id=d.id
            start with
                id in (select id from mydata)
            connect by prior
                parent_id=id
        )
)
where
    id=groupid -- filter out redundant rows required by the analytic function

Is this a reasonable way to achieve the goal of a dense view on sparse hierarchical properties, or is there a better way (more efficient, more comprehensible)?

share|improve this question
    
I was thinking about using something along the lines of SELECT level, id, perent_id, NVL(color, prior color) and realized it would not work. :) –  Krumia Jul 10 '14 at 13:52
    
hi - yeah me too :) only good so long as you have data every other row –  Andy Jul 10 '14 at 15:30
1  
if this is not something performance critical, you could write a recursive function that would return the inherited value, and use it like NVL(color, Get_Inherited_Color(parent_id). With PRAGMA RESTRICT_REFERENCES(WNDS, WNPS, RNPS) oracle will probably cache the values for you (I'm not sure though). –  Krumia Jul 11 '14 at 3:29

1 Answer 1

up vote 2 down vote accepted

I would propose to use a recursive WITH clause to build the hierarchy and use DENSE_RANK to determine the relevant properties:

WITH mydata AS
  (SELECT 1 AS id,NULL AS parent_id,'A' AS name FROM DUAL
   UNION ALL SELECT 2,1,'B' FROM DUAL
   UNION ALL SELECT 3,2,'C' FROM DUAL
   UNION ALL SELECT 4,1,'D' FROM DUAL),
myproperties AS
  (SELECT 1 AS id,'me' AS owner, 'red' AS colour FROM DUAL
   UNION ALL SELECT 2,'you','blue' FROM DUAL
   UNION ALL SELECT 3,'all',NULL FROM DUAL
   UNION ALL SELECT 4,NULL,'green' FROM DUAL),
myhierarchy (id,ancestor,depth) AS --recursive
  (SELECT d.id,d.id,0 FROM mydata d
   UNION ALL SELECT d.id,h.id,h.depth+1
               FROM myhierarchy h
                 INNER JOIN mydata d ON d.parent_id = h.id)
SELECT h.id
      ,MAX(p.owner) KEEP (DENSE_RANK FIRST ORDER BY NVL2(p.owner,1,2),h.depth) owner
      ,MAX(p.colour) KEEP (DENSE_RANK FIRST ORDER BY NVL2(p.colour,1,2),h.depth) colour
  FROM myhierarchy h
    INNER JOIN myproperties p ON p.id=h.ancestor
  GROUP BY h.id;

Update: I added NVL2(*,1,2) in the ORDER BY clause of DENSE_RANK to have NULL values at the end. So NULL values will not overwrite the properties values.

share|improve this answer
    
Hiya this is very cool. However I think I wasn't exact enough in my specifications, though - your answer requires that each row in myproperties specifies every property value - is this correct? Ideally a property row could specify some of the values. I'll modify my question to better indicate this. –  Andy Jul 15 '14 at 11:49
    
I added NVL2(*,1,2) in the ORDER BY clause of DENSE_RANK to have NULL values at the end. So NULL values will not overwrite the properties values. –  Jan Jul 15 '14 at 18:49

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

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