Oracle FAQ Your Portal to the Oracle Knowledge Grid
HOME | ASK QUESTION | ADD INFO | SEARCH | E-MAIL US
 

Home -> Community -> Usenet -> c.d.o.server -> Re: Nested Coalescing possible in SQL?

Re: Nested Coalescing possible in SQL?

From: Lennart Jonsson <lennart_at_kommunicera.umea.se>
Date: 4 Jun 2004 00:00:44 -0700
Message-ID: <6dae7e65.0406032300.77888608@posting.google.com>


jlanfield2003_at_yahoo.com (Jeff Lanfield) wrote in message news:<235c483f.0406031837.62f2701_at_posting.google.com>...
> Thanks Lennart. I think your third suggestion might do the trick. If
> you have a chance to answer I'm curious:
>
> 1) Why do you think storing the path (suggestion #2) is not an option?
> Or if it is option, why is it a bad idea compared to storing a
> separate ancestor relation? (aside from the usual normal form
> reasoning)
>

Since youre mainly concerned in retrieving ancestors, (not investigating subtree
), I think it is a bit clumsy. Assume that you have a node x with path 1.2.3.56.89.112 and want to investigate which nodes in the path that have property p. How would you do that? Subtree queries are much easier since you can query: where path like '1.2.4.6.%'

> 2) How would you structure the query if you stored the path
> (suggestion #2).
>

I would figure out a way to retrive ancestors and then use the same way.

If I where in your shoes I would encapsulate the ancestor stuff in views or table functions, and then use those in my queries. If you decide to go for another aproach, you rewrite the functions/views and can continue to use the queries. Simple example using table functions in db2:

CREATE FUNCTION SUBTREE (ID INTEGER)

        RETURNS TABLE (NODEID INTEGER) 
        LANGUAGE SQL 
        READS SQL DATA 
        NO EXTERNAL ACTION 
        DETERMINISTIC 
        RETURN 
                select nodeid from ancestor where ancestorid = ID
@

CREATE FUNCTION SUBTREE_SELF (ID INTEGER)

        RETURNS TABLE (NODEID INTEGER) 
        LANGUAGE SQL 
        READS SQL DATA 
        NO EXTERNAL ACTION 
        DETERMINISTIC 
        RETURN 
                select s.nodeid from table(subtree(ID)) as s 
                union all 
                values (ID)

@

drop ...

CREATE FUNCTION SUBTREE (ID INTEGER)

        RETURNS TABLE (NODEID INTEGER) 
        LANGUAGE SQL 
        READS SQL DATA 
        NO EXTERNAL ACTION 
        DETERMINISTIC 
        RETURN 
                select nodeid from tree where path like (ID  || '.%')

etc

The same goes for depth

As a bonus it will simplify your original query. I.e

with suspects (nodeid, ancestorid, depth) as (

   select

         ps.nodeid, ps.ancestorid, depth_func(ps.nodeid) as depth
     from data d, tree t, table(path_self(t.nodeid)) ps
     where ps.ancestorid = d.nodeid and d.color is not null
)
select ...

HTH
/Lennart

> Thanks!
>
> - Jeff
>
>
>
> lennart_at_kommunicera.umea.se (Lennart Jonsson) wrote in message news:<6dae7e65.0406022337.338870_at_posting.google.com>...
> > jlanfield2003_at_yahoo.com (Jeff Lanfield) wrote in message news:<235c483f.0406021038.13a1b83b_at_posting.google.com>...
> >
> > [...]
> >
> > >
> > > So say the tree is specified like this:
> > >
> > > (nodeId int, parentId int, color varchar, phone varchar)
> > >
> > > 5, 0,"GREEN", "555-1212"
> > > 7, 5, NULL, "777-5555"
> > > 8, 7 NULL, NULL
> > > 9, 7 "BLUE", NULL

> > >
> > >
> > > That is: node 7 inherits values from 5. Nodes 8,9 inherit values from
> > > 7. Node 5 is the top level node.
> > >
> > > I want to run a query that would give the following result set:
> > >
> > > select nodeId, color, phone from ...
> > >
> > > 5,"GREEN", "555-1212"
> > > 7,"GREEN", "777-5555"
> > > 8,"GREEN", "777-5555"
> > > 9,"BLUE", "777-5555"
> > >
> > > Can such a query be constructed?
> > >
> >
> > If you dont have a maximum depth of your tree (and cannot use
> > recursion), then no. The reason is that you cannot express queries
> > like "gimmie the ancestors of x". What you need to do is to inform
> > your system that 5 is an ancestor of 9. There are several ways of
> > doing this. Troels Arvin has a page with links to articles on the
> > subject:
> >
> > http://troels.arvin.dk/db/rdbms/links/#hierarchical
> >
> > 1. Nested set: google for Celko and nested. There are also variants of
> > this.
> > 2. Store the path in each node. In your case something like:
> >
> > 5,'',"GREEN", "555-1212"
> > 7,'5',"GREEN", "777-5555"
> > 8,'5.7',"GREEN", "777-5555"
> > 9,'5.7',"BLUE", "777-5555"
> >
> > In your case I dont think this is an option
> >
> > 3. Store a separate ancestor relation. In your case
> >
> > create table ancestor (
> > nodeid int not null
> > references tree,
> > ancestorid int not null
> > references tree,
> > primary key (nodeid, ancestorid)
> > );
> >
> > insert into ancestor values (7,5), (8,7), (8,5), (9,7), (9,5);
> >
> > Main drawback is that you have to maintain this relation as you
> > modifies your tree. I have some notes on how that can be achieved:
> >
> > http://fungus.teststation.com/~jon/treehandling/TreeHandling.htm
> >
> >
> >
> > Anyhow, once you have a way of asking for ancestors for a given node,
> > you can do what you want in a single query, namely:
> >
> > find the ancestor at the largest depth with property p
> >
> > Assuming the following ddl
> >
> > create table tree (
> > nodeid int not null primary key,
> > parent int not null
> > references tree
> > on delete restrict
> > );
> >
> > create table data (
> > nodeid int not null primary key
> > references tree
> > on delete cascade,
> > color varchar(10),
> > phone varchar(10)
> > );
> >
> > insert into tree values (5,5), (7,5), (8,7), (9,7);
> > insert into data values (5, 'GREEN', '555-1212'), (7, NULL,
> > '777-5555'), (8, NUL
> > L, NULL), (9, 'BLUE', NULL);
> >
> > create table ancestor (
> > nodeid int not null
> > references tree,
> > ancestorid int not null
> > references tree,
> > primary key (nodeid, ancestorid)
> > );
> >
> > insert into ancestor values (7,5), (8,7), (8,5), (9,7), (9,5);
> >
> > You could use a query like:
> >
> > with suspects (nodeid, suspectid, depth) as (
> > select
> > a.nodeid, a.ancestorid,
> > (select count(1) from ancestor where nodeid = a.ancestorid) as
> > depth
> > from ancestor a, data d
> > where a.ancestorid = d.nodeid
> > and d.color is not null
> > union all
> > select
> > d.nodeid, d.nodeid,
> > (select count(1) from ancestor where nodeid = d.nodeid) as
> > depth
> > from data d
> > where d.color is not null
> > and not exists (
> > select 1 from ancestor where ancestorid = d.nodeid
> > )
> > )
> > select s.nodeid, d.color from suspects s, data d
> > where d.nodeid = s.suspectid
> > and depth = (select max(depth) from suspects where nodeid =
> > s.nodeid)
> >
> > NODEID COLOR
> > ----------- ----------
> > 7 GREEN
> > 8 GREEN
> > 9 BLUE
> >
> > 3 record(s) selected.
> >
> > As you can see node 5 is missing, but I'll leave that for you ;-)
> >
> >
> > HTH
> > /Lennart
> >
> >
> > > - Jeff
Received on Fri Jun 04 2004 - 02:00:44 CDT

Original text of this message

HOME | ASK QUESTION | ADD INFO | SEARCH | E-MAIL US