I am providing one example here to make you all understand what i actually need:
I have a table like this:
Name Null? Type
----------------------------------------- -------- --------------
Child_ID NUMBER(10)
Father_ID NUMBER(10)
Values are:
Child_ID Father_ID
---------- ----------
2 1
4 1
3 2
5 3
Now I want the hierarchical information for Father id 1. For that I have wrote one query and that is providing me the exact output:
**select * from child
start with father_id=1
connect by prior child_id = father_id;**
O/P:
Child_ID Father_ID
---------- ----------
2 1
3 2
5 3
4 1
Now I want the o/p should be like this:
ID
-----
1
2
3
4
5
I can get it easily by using union key but I don't want to use that.
Is there any other way to get this?
Thanks in advance.
It's a bit messy but you could do :
select distinct case when l=1 then child_id else father_id end id
from
(select child_id, father_id
from child
start with father_id=1 connect by prior child_id=father_id) child
cross join (select level l from dual connect by level < 3)
order by id
;
Related
I have tbl_parent like this in Oracle SQL, sample data is given below:
Id(primary key) parentid childid
1 1 2
2 1 3
3 2 1
4 3 1 -- This row is wrong
In above table, some rows are incorrectly inserted, for example, if parent_id 1 has child_id 3 then parent_id 3 should not have child_id 1 as 3 is already child of 1 so can not be parent, I have 5000+ rows and want to find these incorrect rows, any help please?
greatest and least functions might be used as
select least(parentid,childid) as least_par_chi_id,
greatest(parentid,childid) as greatest_par_chi_id
from tab
group by greatest(parentid,childid), least(parentid,childid)
having count(*)>1;
Basically you are looking for cycles in your table.
The Oracle functionality to indentify cycles in hierarchical query is
CONNECT BY NOCYCLE and CONNECT_BY_ISCYCLE
This query show all nodes that lead to cycle - column is_Cycle = 1
select tbl.* ,
CONNECT_BY_ISCYCLE is_Cycle,
SYS_CONNECT_BY_PATH(childid, '/') path
from tbl
CONNECT BY NOCYCLE PRIOR childid = parentid
For your data the result is
PARENTID CHILDID IS_CYCLE PATH
---------- ---------- ---------- ----------
1 2 0 /2
2 1 1 /2/1
1 3 1 /2/1/3
1 3 0 /3
3 1 1 /3/1
1 2 1 /3/1/2
2 1 0 /1
1 2 1 /1/2
1 3 1 /1/3
3 1 0 /1
1 2 1 /1/2
1 3 1 /1/3
Note taht each cycle is recognised on several places, so you get some redundant data.
The advantage of this apprach is, that it works for longer cycles too (where the simple GROUP BY approach fails).
Example for cycle of the length 3:
create table tbl as
select 1 parentid, 2 childid from dual union all
select 2 parentid, 3 childid from dual union all
select 3 parentid, 1 childid from dual;
PARENTID CHILDID IS_CYCLE PATH
---------- ---------- ---------- ----------
1 2 0 /2
2 3 0 /2/3
3 1 1 /2/3/1
2 3 0 /3
3 1 0 /3/1
1 2 1 /3/1/2
3 1 0 /1
1 2 0 /1/2
2 3 1 /1/2/3
I have a situation where a particular child object may have multiple parents of different types. For example, a foo object may be a child of one ore more of a, b, or c objects. More over, I also have a bar object which may also be a child of one or more a, b, or c objects. What's the proper way to model this in SQL?
A) Single table for all relationships:
relationship_tbl
parent_id parent_type child_id child_type
--------- ----------- -------- ----------
1 a 5 foo
2 a 6 foo
3 c 7 bar
4 b 7 bar
B) Unique table for each parent type:
a_child_tbl
parent_id child_id child_type
--------- -------- ----------
1 5 foo
2 6 foo
b_child_tbl
parent_id child_id child_type
--------- -------- ----------
4 7 bar
c_child_tbl
parent_id child_id child_type
--------- -------- ----------
3 7 bar
C) Unique table for each child type:
foo_parent_tbl
child_id parent_id parent_type
--------- ----------- -----------
5 1 a
6 2 a
bar_parent_tbl
child_id parent_id parent_type
--------- ----------- -----------
7 3 c
7 4 b
D) Unique table for each combination
a_foo_tbl
parent_id child_id
--------- --------
1 5
2 6
b_bar_tbl
parent_id child_id
--------- --------
4 7
c_bar_tbl
parent_id child_id
--------- --------
3 7
E) Some other strategy that I haven't explored
To me, it seems like A would be the easiest to query and answer questions like Find all the parents of child 7 or Find all the children of parent 4, but I've read some advice that basically says never create generic tables for parent/child relationships.
Could somebody shed some light on the best way to do this and why? It's safe to assume that the table will never have more than a few million rows in it.
I'd recommend a variation of your solution C.
You need to have a separate M:N table for each M:N relationship, per Fourth Normal Form.
But also create a supertable to unify all the a, b, c parent types, so that the M:N tables can reference a single table, in which each parent_id is strictly assigned its respective type.
parent_tbl
parent_id parent_type
--------- -----------
1 a
2 a
3 c
4 b
a_parent_tbl
parent_id parent_type
--------- -----------
1 a
1 a
b_parent_tbl
parent_id parent_type
--------- -----------
4 b
c_parent_tbl
parent_id parent_type
--------- -----------
3 c
In each sub-parent table, the parent_type is restricted to a single value. The parent_table has a unique constraint on (parent_id, parent_type), and the foreign key in each sub-parent tables references the columns in that unique constraint. Therefore no parent_id can be referenced by more than one sub-type.
Then your child M:N tables only need to reference parent_table by ID. You don't necessarily need a parent_type column in these tables, but you do if you need to create a UNIQUE constraint over (child_id, parent_type) so that each child can have only one parent of a given type.
foo_parent_tbl
child_id parent_id
-------- ---------
5 1
6 2
bar_parent_tbl
child_id parent_id
-------- ---------
7 3
7 4
You may also like to read:
My past answers to questions on polymorphic-associations.
My presentation Practical Object Oriented Models In SQL
My book SQL Antipatterns Volume 1: Avoiding the Pitfalls of Database Programming
As long as types a,b,c,d are always parents, and types foo and bar can only be children (i.e. 'foo' could/will never be a parent of 'c') You should have a table for each entity and a table for the relationships. One table for parents (parent_id, parent_type), One table for children (child_id, child_type), and One table for relationships (parent_id, child_id).
I have a table with such rows:
ID Parent_ID Name
1 (null) A
2 1 B
3 1 C
4 2 D
5 3 E
6 5 F
7 (null) G
8 (null) H
I need to get IDs of all related rows no matter if Name='A' or 'F' is passed as criteria. In this case I should receive all ID beside 7 and 8.
I tried lot of examples and read a lot of articles but I give up now. Can you help with it?
with
t as (
select id
from your_table
where name = 'D' -- your starting point
)
select id
from (
select id, parent_id from your_table
where parent_id is not null
union all
select parent_id, id from your_table
where parent_id is not null
union all
select id, null from t
)
start with parent_id is null
connect by nocycle prior id = parent_id
fiddle
A is at the root of a hierarchy (it's the parent of B, which is the parent of D, etc.). To start with A and work down to F (and also down to D and E, which also have A as a parent through different routes):
SELECT ID, Parent_ID, Name
FROM tbl
START WITH Name = 'A'
CONNECT BY PRIOR ID = Parent_ID
F is at the end of a hierarchy. Oracle calls this a "leaf". To start with leaf F and work up to A at the top:
SELECT ID, Parent_ID, Name
FROM tbl
START WITH Name = 'F' -- start with F instead of A
CONNECT BY PRIOR Parent_ID = ID -- switch the CONNECT BY to work up
Oracle has a SYS_CONNECT_BY_PATH function that's great for visualizing the hierarchy. Here's how to use it in the first query (A down to F):
SELECT ID, Parent_ID, Name, SYS_CONNECT_BY_PATH(Name, '/') AS Path
FROM tbl
START WITH Name = 'A'
CONNECT BY PRIOR ID = Parent_ID
Results:
ID PARENT_ID NAME PATH
---- ---------- ---- -----------
1 A /A
2 1 B /A/B
4 2 D /A/B/D
3 1 C /A/C
5 3 E /A/C/E
6 5 F /A/C/E/F
You can use any delimeter you want as the second argument to SYS_CONNECT_BY_PATH.
I have a table describing elements organized in a tree-like structure:
ID, PARENT_ID, NAME
0 null TOP
1 0 A
2 0 B
3 0 C
4 1 AA
5 2 BA
6 3 CA
7 6 CAA
...
There can be many levels in this hierarchy.
Suppose there is a list of elements (say IDs 2 and 3) for which I would like to get all child records from the table.
Something like this:
select *
from MY_TABLE
start with PARENT_ID in (2,3)
connect by PARENT_ID = prior ID
will return:
ID, PARENT_ID, NAME
5 2 BA
6 3 CA
7 6 CAA
However, I want the each output record to be mapped to the original parent from my list (2,3) so that the output would look like this:
ORIGINAL_PARENT_ID, ID, PARENT_ID, NAME
2 5 2 BA
3 6 3 CA
3 7 6 CAA
How can it be done?
connect_by_root may be what you're after?
SQL> select t.*, connect_by_root parent_id as ORIGINAL_PARENT_ID
2 from MY_TABLE t
3 start with PARENT_ID in (2,3)
4 connect by PARENT_ID = prior ID
5 /
ID PARENT_ID NAM ORIGINAL_PARENT_ID
---------- ---------- --- ------------------
5 2 BA 2
6 3 CA 3
7 6 CAA 3
Assuming your names are really as you have them, then the problem can be done without connect by. You can use simple string manipulation.
with ToFind (
select 'C' as parent from dual union all
select 'B' as parent from dual
)
select t.*
from t join
ToFind tf
on t.name like tf.parent, 100)||'%' and t.name <> tf.parent
I have the following table structure:
table Parent (Id)
table Child (ParentId, SortOrder, Id, Data)
Normal data should look like this in the Child table:
ParentId SortOrder Id Data
-------- --------- ---- ----
1 0 100 'Samuel'
1 1 101 'Levi'
1 2 102 'Isaac'
2 0 103 'Emma'
3 0 104 'Maddison'
Unfortunately, something has become corrupted to make the data look like this:
ParentId SortOrder Id Data
-------- --------- ---- ----
1 2 100 'Samuel'
1 4 101 'Levi'
1 5 102 'Isaac'
2 3 103 'Emma'
3 0 104 'Maddison'
How can I identify, through SQL, parents with children that are not properly ordered through my zero-based SortOrder column?
In the above example, the SQL query would tell me that ParentId 1 and 2 are invalid.
You can compare the generated Row_number against the recorded sortorder
select distinct ParentId
from
(
select *, rn=ROW_NUMBER() over (partition by parentid order by sortorder) -1
from Child
) X
where rn <> Sortorder