Undirected graph in Oracle SQL - sql

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

Hierarchical Connect By Pass Value to children

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)

SQL Modeling Pyramid or Binary Tree

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

Recursive SQL and information on different level

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.

Oracle flex value hierarchy SQL query for oracle ebs r12 report

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

T-SQL Count child node in Binary Tree?

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.