I'm trying to represent undirected graph in Oracle SQL, for example, I have stations graph:
CREATE TABLE station (
station_id INTEGER NOT NULL
);
CREATE TABLE station_link (
from_station INTEGER NOT NULL,
to_station INTEGER NOT NULL
);
This is obviously directed graph, but I have no idea, how to make it undirected.
Point: I need to get all vertices, which have path to current vertex and information about their level (how many vertices on this path).
For directed graph it is pretty easy:
SELECT sl.to_station, LEVEL
FROM station_link sl
START WITH sl.from_station = :curVertex
CONNECT BY NOCYCLE PRIOR sl.to_station = sl.from_station
But so we will get only one-way verticies.
Question: Do this problem have solution, except adding additional links (2 -> 1 for 1 -> 2)?
There is sql fiddle for tests: http://sqlfiddle.com/#!4/6c09e/24
For a "fast win" you can use your structure "as is", but for every edge you shold have two records in station_link table.
If you want "not_so_fast_but_without_doble_edge_records_please win", you can use this weirdo-trick:
SELECT
x.TO_STATION,
x.LVL
FROM (
SELECT sl.to_station, LEVEL as lvl
FROM station_link sl
START WITH sl.from_station = :curVertex
CONNECT BY NOCYCLE PRIOR sl.to_station = sl.from_station
UNION ALL
SELECT sl.from_station as to_station , LEVEL as lvl
FROM station_link sl
START WITH sl.to_station = :curVertex
CONNECT BY NOCYCLE PRIOR sl.from_station = sl.to_station
) x
It will do the work. Actually, it just combines two traversal directions.
But if I'll want to implement some serious algorithms on graphs in PLSQL, I would look to SDO_GEOMETRY data type and Oracle Spatial And Graphs Datasheets.
Related
I have a hierarchical SQL Statement, which show me a hierarchical list of components of a product. For example: Part 1101400004 contains Part 1012444. And Part 1012444 contains B30048. For each component i have a Qty.
Now my question is: is it possible, to pass a value to the children?
So when part 1101400004 has QTY 0, no matter what QTY Part 1012444 has, it should be 0 because the parent part has QTY zero. And this logic to the bottom of the tree.
select part_no, component_part, qty_per_assembly
FROM STRUCTURE MS
CONNECT BY PRIOR MS.COMPONENT_PART = MS.PART_NO
START WITH MS.PART_NO = '1101400004'
Result
Thx for help
From Oracle version 10g you can use CONNECT_BY_ROOT pseudocolumn like this:
select part_no, component_part, connect_by_root qty_per_assembly
FROM STRUCTURE MS
CONNECT BY PRIOR MS.COMPONENT_PART = MS.PART_NO
START WITH MS.PART_NO = '1101400004'
See https://docs.oracle.com/cd/B19306_01/server.102/b14200/queries003.htm#i2069380
As I understand you need to get quantity from qty_per_assembly if all prents not equal "0" and "0" if at least one predecessor is equal "0". For solve it you may use combintion of connect_by_root(component_part) and analytic MIN. Please correct me if I wrong
select part_no, component_part, DECODE(MIN(qty_per_assembly) OVER (PARTITION BY connect_by_root(component_part) ORDER BY level)
, 0
, 0
, qty_per_assembly)
FROM STRUCTURE MS
CONNECT BY PRIOR MS.COMPONENT_PART = MS.PART_NO
START WITH MS.PART_NO = '1101400004'
EDIT: connect_by_root(qty_per_assembly) change to connect_by_root(component_part)
I'm building a sql server project that have a pyramid or binary tree concept...
I gonna try to explain using some tables!
The first table is
TB_USER(ID, ID_FATHER, LEFT/RIGHT TREE POSITION)
User can sell producs! So when they sell they earn points. Then, the second table is
TB_SELL (ID_USER, ID_PRODUCT, POINT)
As a result I'd like to see in the report format of points of each client below me in the binary model tree. How can I design these tables to make my life easier in this kind of search ? I will always get my soons up to 9 levels down.
I know that with procedure I can solve this problem , however I would like to know an elegant and simple solution.
Thank you
I solve this using a with a recursive query:
with with_user_earns as (
-- get father information (start)
select father.id, father.str_name, father.id_father, father.ind_father_side_type, 1 as int_user_level from tb_user father where id = 9
union all
-- get all soons (stop condition)
select son.id, son.str_name, son.id_father, son.ind_father_side_type, WUE.int_user_level + 1 from tb_user as son inner join with_user_earns as WUE on son.id_father = WUE.id where son.id_father is not null /*and WUE.int_user_level < 9*/
)
-- show result
select with_user_earns.id, with_user_earns.str_name, with_user_earns.id_father, with_user_earns.ind_father_side_type, with_user_earns.int_user_level from with_user_earns order by with_user_earns.int_user_level, with_user_earns.id
Is it possible to display, in the same query, information concerning different level of recursivity ?
select LEVEL, ae2.CAB, ae2.NIVEAU, ae2.ENTITE, ae2.ENTITE_PARENT, ae2.libelle
from my_table ae2
where ae2.NIVEAU = 2
start with ae2.cab = 'XXX'
connect by prior ae2.entite_parent = ae2.entite
With this query I have (let's say) 4 levels of information about the entity above root 'XXX'
Is it possible to display root information at the same time?
Yes, it's possible to use the CONNECT_BY_ROOT operator. For instance, if you wanted the cab of the parent your query would be:
select connect_by_root cab
, level, cab, niveau, entite, entite_parent, libelle
from my_table
where niveau = 2
start with cab = 'XXX'
connect by prior entite_parent = entite
You have to use a new operator for each column you want to select. You won't get information from a "different" level of recursivity using this operator, only from the root. If you want more you'll have to use recursive subquery factoring.
I am new to oracle and oracle ebs and I need some help.
I am doing a report in oracle ebs r12 and I need to list flex values from fnd_flex_values_vl view in a hierarchical way using a SQL query. It doesn`t necessary has to be a hierarchial query. Any query will do. I just need a SQL statement that will return me flex values in their hierarchial way.
There are two objects, that store information about flex values hierarchy. It is FND_FLEX_VALUE_NORM_HIERARCHY (table) and fnd_flex_value_children_v (view). I assume one of these is enough, since fnd_flex_value_children_v is made using FND_FLEX_VALUE_NORM_HIERARCHY and some other objects.
However, the problem I faced is, that several parents may be listed for one flex value and that I need to find all top parents or leaves in order to do an up-bottom or bottom-up hierarchy. As far as I understand fnd_flex_value_children_v doesn`t necessary store top parents (stores only children).
Also it seems that there is probably not one, but there may be multiple hierarchies (if so, I need to list them all in one query).
Your help will be really appreciated. I`ve been struggling with this one quite a while.
Thank you very much for your attention.
Best regards, new user. =)
You should use the table, APPLSYS.FND_FLEX_VALUE_SETS. The objects you identify are metadata objects about the FND_FLEX_VALUE_SETS table.
I like to start with the root record.
Here is my method to find root records (no parent).
SELECT DISTINCT
FVS.PARENT_FLEX_VALUE_SET_ID
FROM
APPLSYS.FND_FLEX_VALUE_SETS FVS
WHERE
FVS.PARENT_FLEX_VALUE_SET_ID IS NOT NULL
ORDER BY 1 ;
Once I find the root record, I develop my start by clause:
START WITH
(
FVS.FLEX_VALUE_SET_ID IN
(SELECT DISTINCT FVS.PARENT_FLEX_VALUE_SET_ID
FROM APPLSYS.FND_FLEX_VALUE_SETS FVS
WHERE FVS.PARENT_FLEX_VALUE_SET_ID IS NOT NULL
)
This clause does capture all root records (you could select just one).
Next, I develop my connect by clause. Since I want my hierarchy to start at the root, I would take this approach:
level 1 flex_value_set_id ....prior level
level 2 parent_flex_value_set_id
CONNECT BY fvs.parent_flex_value_set_id = prior fvs.flex_value_set_id ;
This results in this statement:
SELECT LEVEL,
FVS.*
FROM APPLSYS.FND_FLEX_VALUE_SETS FVS
START WITH
(
FVS.FLEX_VALUE_SET_ID IN
(SELECT DISTINCT FVS.PARENT_FLEX_VALUE_SET_ID
FROM APPLSYS.FND_FLEX_VALUE_SETS FVS
WHERE FVS.parent_flex_value_set_id IS NOT NULL
)
)
CONNECT BY FVS.PARENT_FLEX_VALUE_SET_ID = PRIOR FVS.FLEX_VALUE_SET_ID ;
One then can add the flex values as follows:
SELECT
LEVEL,
FVS.*
FROM
(SELECT
FLEX.FLEX_VALUE_SET_ID,
FLEX.PARENT_FLEX_VALUE_SET_ID,
FLEX.FLEX_VALUE_SET_NAME,
FVAL.FLEX_VALUE
FROM
APPLSYS.FND_FLEX_VALUE_SETS FLEX,
APPLSYS.FND_FLEX_VALUES FVAL
WHERE
FLEX.FLEX_VALUE_SET_ID = FVAL.FLEX_VALUE_SET_ID(+)) FVS
START WITH
(FVS.FLEX_VALUE_SET_ID IN
(SELECT DISTINCT
FVS.PARENT_FLEX_VALUE_SET_ID
FROM APPLSYS.FND_FLEX_VALUE_SETS FVS
WHERE FVS.parent_flex_value_set_id IS NOT NULL ) )
CONNECT BY
FVS.PARENT_FLEX_VALUE_SET_ID = PRIOR FVS.FLEX_VALUE_SET_ID;
May be this can help u
SELECT fvc.PARENT_FLEX_VALUE RUBRO_N0 ,FVT.description
DESC_RUBRO_N0,FVC.FLEX_VALUE RUBRO_N1 , fvc.DESCRIPTION
DESC_RUBRO_N1,FVC2.FLEX_VALUE RUBRO_N2 , FVC2.DESCRIPTION
DESC_RUBRO_N2,FVC3.FLEX_VALUE RUBRO_N3 , FVC3.DESCRIPTION
DESC_RUBRO_N3,FVC4.FLEX_VALUE RUBRO_N4 , FVC4.DESCRIPTION
DESC_RUBRO_N4,NVL(FVC4.FLEX_VALUE,NVL(FVC3.FLEX_VALUE,NVL(FVC2.FLEX_VALUE,FVC.FLEX_VALUE))) RUBROFIN
FROM FND_FLEX_VALUE_CHILDREN_V fvc
,FND_FLEX_VALUE_CHILDREN_V FVC2
,FND_FLEX_VALUE_CHILDREN_V FVC3
,FND_FLEX_VALUE_CHILDREN_V FVC4
,FND_FLEX_VALUES_TL FVT
WHERE fvc.FLEX_VALUE_SET_ID = 1016176
AND fvc.PARENT_FLEX_VALUE not in(SELECT FLEX_VALUE FROM FND_FLEX_VALUE_CHILDREN_V WHERE FLEX_VALUE_SET_ID = --YOUR FLEX_VALUE_SET_ID)
AND fvc.FLEX_VALUE = FVC2.PARENT_FLEX_VALUE (+)
AND fvc2.FLEX_VALUE = FVC3.PARENT_FLEX_VALUE (+)
AND fvc3.FLEX_VALUE = FVC4.PARENT_FLEX_VALUE (+)
AND fvc.PARENT_FLEX_VALUE = FVT.FLEX_VALUE_MEANING
AND FVT.SOURCE_LANG = 'ESA'
AND FVT.LANGUAGE = 'ESA' AND FVT.LAST_UPDATE_LOGIN NOT IN (0)
ORDER BY 1,2,3,5,7
;
Best Regards
This SQL from the Blitz Report library returns the hierarchy structure based on fnd_flex_value_norm_hierarchy with all containing child flex values: https://www.enginatics.com/reports/fnd-flex-value-hierarchy/
select
lpad(' ',2*(level-1))||level level_,
lpad(' ',2*(level-1))||ffvnh.parent_flex_value value,
ffvv.description,
decode(ffvnh.range_attribute,'P','Parent','C','Child') range_attribute,
ffvnh.child_flex_value_low,
ffvnh.child_flex_value_high,
decode(connect_by_isleaf,1,'Yes') is_leaf,
connect_by_root ffvnh.parent_flex_value root_value,
substr(sys_connect_by_path(ffvnh.parent_flex_value,'-> '),4) path,
ffvnh.parent_flex_value value_flat
from
(
select
ffvnh.parent_flex_value,
ffvnh.child_flex_value_low,
ffvnh.child_flex_value_high,
ffvnh.range_attribute,
ffvnh.flex_value_set_id
from
fnd_flex_value_norm_hierarchy ffvnh
where
ffvnh.flex_value_set_id=(select ffvs.flex_value_set_id from fnd_flex_value_sets ffvs where ffvs.flex_value_set_name=:flex_value_set_name)
union all
select
ffv2.flex_value parent_flex_value,
null child_flex_value_low,
null child_flex_value_high,
'x' range_attribute,
ffv2.flex_value_set_id
from
fnd_flex_values ffv2
where
2=2 and
ffv2.summary_flag='N' and
ffv2.flex_value_set_id=(select ffvs.flex_value_set_id from fnd_flex_value_sets ffvs where ffvs.flex_value_set_name=:flex_value_set_name)
) ffvnh,
fnd_flex_values_vl ffvv
where
3=3 and
ffvnh.parent_flex_value=ffvv.flex_value and
ffvnh.flex_value_set_id=ffvv.flex_value_set_id
connect by nocycle
ffvnh.parent_flex_value between prior ffvnh.child_flex_value_low and prior ffvnh.child_flex_value_high and
decode(nvl(prior ffvnh.range_attribute,'P'),'P','Y','N')=ffvv.summary_flag
start with
ffvnh.parent_flex_value=:parent_flex_value and
1=1 and
(:parent_flex_value is not null or
not exists (select null from
fnd_flex_value_norm_hierarchy ffvnh0
where
ffvnh0.flex_value_set_id=(select ffvs.flex_value_set_id from fnd_flex_value_sets ffvs where ffvs.flex_value_set_name=:flex_value_set_name) and
ffvnh.parent_flex_value between ffvnh0.child_flex_value_low and ffvnh0.child_flex_value_high and
ffvv.summary_flag=decode(ffvnh0.range_attribute,'P','Y','N')
)
)
To see all hierarchies (different parent top values), remove the 'start with' restriction to the parent flex value:
ffvnh.parent_flex_value=:parent_flex_value
I made a table to store a Binary Tree like below:
- NodeID
- NodeLeft
- NodeRight
NodeLeft store the ID of the left node. And Node right store the ID of the right node.
I need to write a Procedure that if i pass a NodeID, it'll count how many child node on the left and how many child node on the right. Can separate to 2 Procedure.
Try this:
WITH CTE_Node(
NodeID,
NodeRigth,
NodeLeft,
Level,
RigthOrLeft
)
AS
(
SELECT
NodeID,
NodeRigth,
NodeLeft,
0 AS Level,
'P'
FROM Node
WHERE NodeID = 1
UNION ALL
SELECT
Node.NodeID,
Node.NodeRigth,
Node.NodeLeft,
Level + 1,
CASE WHEN CTE_Node.NodeLeft = Node.NodeID THEN 'R' ELSE 'L' END
FROM Node
INNER JOIN CTE_Node ON CTE_Node.NodeLeft = Node.NodeID
OR CTE_Node.NodeRigth = Node.NodeID
)
SELECT DISTINCT RigthOrLeft,
COUNT(NodeID) OVER(PARTITION BY RigthOrLeft)
FROM CTE_Node
Here is an SQL Fiddle.
The Level is just there to see how is it working. May you can use it later.
I found this topic.
http://www.sqlservercentral.com/Forums/Topic1152543-392-1.aspx
The table structure is different from my designed table. But it is an Binary Tree so i can use it.
And the SQL Fiddle is very helpful.