Okay this problem will be a little hard to explain but here it goes..
I have a query that pulls in data that is rendered in a tree like visualization. The yloc calculated in this query is used to determine the y location to render certain objects attached to these capabilities at.
Just using the MAX(coalesce(CAP_TREE2.depth),0) doesn’t work. So I wrote an algorithm that shows what I need yloc in certain situations.
Here is the algorithm:
if (capability has c2 !=1)
{
yloc = 0
}
else if (capability is child (at any depth) of capability with c2 != 1)
{
yloc = depth - (depth of first parent with c2 != 1)
}
else
{
y = depth
}
NOTE: c2 represents the childNumber (in alphabetical order). So if a capability has two children “A” and “B”. “A” will have c2 = 1 and “B” will have c2 = 2.
I have had a LOT of trouble trying to implement this algorithm in SQL (Oracle 11g R2).
The issue I’m having trouble finishing is the else if clause in my algorithm.
I have been able to get all of the capabilities that are children (at any depth) of a capability with c2 != 1.
However, the part I haven’t been able to finish is the
yloc = depth – (depth of first parent with c2 !=1)
Can anyone PLEASE show me how to get the “depth of the first parent with c2 !=1” ?
My query would finally be complete if I can get that value.
I will show what values I expect from my sample data for this to try and make it more clear.
“Investment Management” first parent with c2 != 1 is “FPP” which has a depth of 2.
“3rd party Product Management” first parent with c2 != 1 is “FPP” which has a depth of 2.
“Order Management (PI)” first parent with c2 != 1 is “Operations and Services (PI)” with a depth of 2.
Note: Sorry I cannot change the schema.
Here is what I have so far..the bottom select statement is where I am working.
http://sqlfiddle.com/#!4/55b5a/116
Schema SQL:
CREATE TABLE capability
(
id int,
parent_id int,
name varchar(200)
)
;
CREATE TABLE tree
(
descendantid int,
ancestorid int,
depth int
)
;
INSERT INTO capability (id, parent_id, name) VALUES (1, -1, 'BU-Specific Capabilities');
INSERT INTO capability (id, parent_id, name) VALUES (2, 1, 'PI Capability Model');
INSERT INTO capability (id, parent_id, name) VALUES (3, 2, 'Core Business Processing (PI)');
INSERT INTO capability (id, parent_id, name) VALUES (4, 3, 'Institutional Trust Administration (PI)');
INSERT INTO capability (id, parent_id, name) VALUES (5, 2, 'FPP');
INSERT INTO capability (id, parent_id, name) VALUES (6, 5, 'Investment Management');
INSERT INTO capability (id, parent_id, name) VALUES (7, 6, '3rd party Product Management');
INSERT INTO capability (id, parent_id, name) VALUES (8, 2, 'Operations and Shared Services (PI)');
INSERT INTO capability (id, parent_id, name) VALUES (9, 8, 'Order Management (PI)');
INSERT INTO capability (id, parent_id, name) VALUES (10, 8, 'Settlements (PI)');
INSERT INTO capability (id, parent_id, name) VALUES (11, -1, 'Common Core Capabilities');
INSERT INTO tree (descendantid, ancestorid, depth) VALUES (1, 1, 0);
INSERT INTO tree (descendantid, ancestorid, depth) VALUES (2, 1, 1);
INSERT INTO tree (descendantid, ancestorid, depth) VALUES (2, 2, 0);
INSERT INTO tree (descendantid, ancestorid, depth) VALUES (3, 1, 2);
INSERT INTO tree (descendantid, ancestorid, depth) VALUES (3, 2, 1);
INSERT INTO tree (descendantid, ancestorid, depth) VALUES (3, 3, 0);
INSERT INTO tree (descendantid, ancestorid, depth) VALUES (4, 1, 3);
INSERT INTO tree (descendantid, ancestorid, depth) VALUES (4, 2, 2);
INSERT INTO tree (descendantid, ancestorid, depth) VALUES (4, 3, 1);
INSERT INTO tree (descendantid, ancestorid, depth) VALUES (4, 4, 0);
INSERT INTO tree (descendantid, ancestorid, depth) VALUES (5, 1, 2);
INSERT INTO tree (descendantid, ancestorid, depth) VALUES (5, 2, 1);
INSERT INTO tree (descendantid, ancestorid, depth) VALUES (5, 5, 0);
INSERT INTO tree (descendantid, ancestorid, depth) VALUES (6, 1, 3);
INSERT INTO tree (descendantid, ancestorid, depth) VALUES (6, 2, 2);
INSERT INTO tree (descendantid, ancestorid, depth) VALUES (6, 5, 1);
INSERT INTO tree (descendantid, ancestorid, depth) VALUES (6, 6, 0);
INSERT INTO tree (descendantid, ancestorid, depth) VALUES (7, 1, 4);
INSERT INTO tree (descendantid, ancestorid, depth) VALUES (7, 2, 3);
INSERT INTO tree (descendantid, ancestorid, depth) VALUES (7, 5, 2);
INSERT INTO tree (descendantid, ancestorid, depth) VALUES (7, 6, 1);
INSERT INTO tree (descendantid, ancestorid, depth) VALUES (7, 7, 0);
INSERT INTO tree (descendantid, ancestorid, depth) VALUES (8, 1, 2);
INSERT INTO tree (descendantid, ancestorid, depth) VALUES (8, 2, 1);
INSERT INTO tree (descendantid, ancestorid, depth) VALUES (8, 8, 0);
INSERT INTO tree (descendantid, ancestorid, depth) VALUES (9, 1, 3);
INSERT INTO tree (descendantid, ancestorid, depth) VALUES (9, 2, 2);
INSERT INTO tree (descendantid, ancestorid, depth) VALUES (9, 8, 1);
INSERT INTO tree (descendantid, ancestorid, depth) VALUES (9, 9, 0);
INSERT INTO tree (descendantid, ancestorid, depth) VALUES (10, 1, 3);
INSERT INTO tree (descendantid, ancestorid, depth) VALUES (10, 2, 2);
INSERT INTO tree (descendantid, ancestorid, depth) VALUES (10, 8, 1);
INSERT INTO tree (descendantid, ancestorid, depth) VALUES (10, 10, 0);
INSERT INTO tree (descendantid, ancestorid, depth) VALUES (11, 11, 0);
Query SQL:
SELECT
cap.name,
max(coalesce(CAP_TREE2.depth,0)) as ydepth,
CASE
WHEN cap.parent_id != -1
THEN DENSE_RANK() OVER (PARTITION BY cap.parent_id ORDER BY cap.name) --child number
ELSE
1
END as c2
FROM capability cap
INNER JOIN tree CAP_TREE2 ON CAP.id = CAP_TREE2.descendantid
group by cap.name, cap.id, cap.parent_id
;
WITH ids(id, c2) AS ( -- Find the ids and the ranks
SELECT
id,
CASE
WHEN parent_id = -1
THEN 1
ELSE
DENSE_RANK() OVER (PARTITION BY parent_id ORDER BY name) --child number
END as c2
FROM capability
),
t(id, depth) AS (
SELECT id, 0 AS depth FROM ids WHERE c2 != 1 -- Take only ranks not equal to one
UNION ALL
SELECT c.id, depth+1 FROM capability c JOIN t ON (c.parent_id = t.id) -- Tree-walking
)
--SELECT DISTINCT cap.name, t.depth
--SELECT DISTINCT cap.name, min(t.depth)
--FROM capability cap JOIN t USING(id)
--group by cap.name
SELECT
cap.name,
CASE
-- cap has childNumber != 1
WHEN DENSE_RANK() OVER (PARTITION BY cap.parent_id ORDER BY cap.name) != 1
THEN 0 -- y = 0
-- cap is child of cap with childNumber != 1
WHEN cap.name IN (SELECT DISTINCT capa.name
FROM capability capa
JOIN t USING(id))
THEN max(coalesce(CAP_TREE2.depth,0)) -- y = depth - (depth of first parent with childNumber != 1)
ELSE max(coalesce(CAP_TREE2.depth,0)) -- y = depth
END as yloc
FROM capability cap
INNER JOIN tree CAP_TREE2 ON CAP.id = CAP_TREE2.descendantid
group by cap.name,
cap.id,
cap.parent_id
Also, here is my desired resultset
NAME DEPTH C2 YLOC
BU-Specific Capabilities 0 1 0 --yloc=depth
Common Core Capabilities 0 1 0 --yloc=depth
PI Capability Model 1 1 1 --yloc=depth
Core Business Processing (PI) 2 1 2 --yloc=depth
FPP 2 2 0 --yloc=0
Operations and Shared Services (PI) 2 3 0 --yloc=0
Institutional Trust Administration (PI) 3 1 3 --yloc=depth
Investment Management 3 1 1 --yloc=depth - (depth of FPP)
3rd party Product Management 4 1 2 --yloc=depth - (depth of FPP)
Order Management (PI) 3 1 1 --yloc=depth -(depth of Operations and..)
Settlements (PI) 3 2 0 --yloc=0
I think you don’t need the tree table, because you declared the relation from parent to child already in the capability table.
When you use the CONNECT BY PRIOR command from oracle it builds you the tree, and allows you determine the depth of the node with the LEVEL pseudo-column.
The only tricky part is to get the first parent node that has a depth > 1. As far as i understood your question this should be c2. The result is in the column
FIRST_PARENT_IN_DEPTH_G_1.