Oracle hierarchical queries data - sql

The link gives a good example for overview on how to use Oracle hierarchical queries. I was trying to generate the below combination of data with the example table tab1 given in the link but struck for a while.Using Oracle version 12.2
PARENT_ID CHILD_ID
-------- ---------
1 2 # the root node and id combination (This is evident by using ROOT_ID,ID)
1 3
1 4
. .
. .
2 5 # How to generate below combination in a select statement ont TAB1 table.
2 6
. .
. .
9 11
SELECT id,
parent_id,
RPAD('.', (level-1)*2, '.') || id AS tree,
level,
CONNECT_BY_ROOT id AS root_id,
LTRIM(SYS_CONNECT_BY_PATH(id, '-'), '-') AS path,
CONNECT_BY_ISLEAF AS leaf
FROM tab1
START WITH parent_id IS NULL
CONNECT BY parent_id = PRIOR id
ORDER SIBLINGS BY id;
Output of the above select statement
ID PARENT_ID TREE LEVEL ROOT_ID PATH LEAF
---------- ---------- -------------------- ---------- ---------- -------------------- ----------
1 1 1 1 1 0
2 1 ..2 2 1 1-2 0
3 2 ....3 3 1 1-2-3 1
4 2 ....4 3 1 1-2-4 0
5 4 ......5 4 1 1-2-4-5 1
6 4 ......6 4 1 1-2-4-6 1
7 1 ..7 2 1 1-7 0
8 7 ....8 3 1 1-7-8 1
9 1 ..9 2 1 1-9 0
10 9 ....10 3 1 1-9-10 0
11 10 ......11 4 1 1-9-10-11 1
12 9 ....12 3 1 1-9-12 1
Diagraph:

The sql query to get the desired output are below:
Solution 1: using CTE
with h ( id, parent_id ) as (
select id ,parent_id from tab1
),
r ( id , parent_id, steps ) as (
select id , id , 0
from h
union all
select r.id, h.parent_id, steps + 1
from h join r
on h.id = r.parent_id
)
select parent_id, id
from r
where parent_id != id
order by parent_id asc;
Solution 2: Using Oracle only connect by query. The CONNECT BY NOCYCLE clause can be used to not traverse cyclical hierarchies if any.
with hier_data as
(
select
connect_by_root id as parent_id
,id
from tab1
connect by parent_id = prior id
order by parent_id,id
)
select * from hier_data
where
parent_id != id;

Related

Oracle hierarchical path as separate row

I have a table like below:
ID PARENT_ID
--- ----------
1 null
2 1
3 2
4 2
5 4
6 4
7 1
8 7
9 1
10 9
11 10
12 9
13 null
14 13
and I want query for get result like this:
ID | PARENT_ID
-----+-----------
1 | 1
2 | 1
2 | 2
3 | 1
3 | 2
3 | 3
4 | 1
4 | 2
4 | 4
5 | 1
5 | 2
5 | 4
5 | 5
...
I used Oracle connected by root and get this result:
ID PATH
--- -----------
1 1
2 1-2
3 1-2-3
4 1-2-4
5 1-2-4-5
....
but it's not that I want.
Is there another way to get result without connected by root (prefer in standard SQL), that get same result from table?
Can anyone help me?
Note: I use an Oracle database
Thanks
The first step is to make a query that will produce for you all the parents above a specific node.
Here is a example of such a query:
select * from
(SELECT parent_id
FROM test
START WITH ID = 4
CONNECT BY ID = PRIOR PARENT_ID) temp
where parent_id is not null
UNION
select ID from test where ID = 4 ;
In the above case, we start with Node 4.
The next step is to use this query, with another query to get the results for all nodes.
(Will produce this soon)
final solution
create table test(
id int,
parent_id int
);
insert into test values (1, null);
insert into test values (2,1);
insert into test values (3,2);
insert into test values (4,2);
select distinct ID, parent_id from
(
SELECT a.parent_id as aParent, b.parent_id as bParent, b.id as ID, a.id as parent_id
FROM test a, test b
START WITH a.ID = b.id
CONNECT BY a.ID = PRIOR a.PARENT_ID
) temp
where not (aParent is not null AND bParent is null)
order by id, parent_id;
Optimized
SELECT distinct b.id as ID, a.id as parent_id
FROM test a, test b
where not (a.parent_id is not null and b.parent_id is null )
START WITH a.ID = b.id
CONNECT BY a.ID = PRIOR a.PARENT_ID order by id, parent_id;;
Boolean Algebra Simplification
SELECT distinct
findNodesAboveMe.id as ID,
pathFollowing.id as parent_id
FROM
test pathFollowing,
test findNodesAboveMe
where
pathFollowing.parent_id is null
OR findNodesAboveMe.parent_id is not null START WITH pathFollowing.ID = findNodesAboveMe.id CONNECT BY pathFollowing.ID = PRIOR pathFollowing.PARENT_ID
order by
id,
parent_id;
Fix for Null parents
select id, parent_id from
(
(SELECT DISTINCT
findNodesAboveMe.id AS ID,
CASE WHEN pathFollowing.parent_id IS NULL
THEN pathFollowing.id
ELSE pathFollowing.parent_id END AS parent_id
FROM
test pathFollowing,
test findNodesAboveMe
WHERE
findNodesAboveMe.parent_id IS NOT NULL
START WITH pathFollowing.ID = findNodesAboveMe.id CONNECT BY pathFollowing.ID = PRIOR pathFollowing.PARENT_ID
)
UNION
SELECT
id,
id AS parent_id
FROM test
) order by id, parent_id
;
Update
select
distinct bid as ID, aid as parent_id
from
(
SELECT DISTINCT
a.id as aid,
a.parent_id as aparentid,
b.id as bid,
b.parent_id as bparentid,
ltrim(sys_connect_by_path(a.id, ','), ',') AS pth
FROM test a, test b
WHERE NOT
(a.parent_id IS NOT NULL AND b.parent_id IS NULL)
START WITH a.ID = b.id
CONNECT BY a.ID = PRIOR a.PARENT_ID
) temp
where ( pth like bid or pth like bid || ','|| bparentid || '%' )
order by ID, parent_id;

sql select parent child recursive in one field

I do not know how to select query recursive..
id idparent jobNO
--------------------------------
1 0 1
2 1 2
3 1 3
4 0 4
5 4 5
6 4 6
how do the results like this With SqlServer
id idparent jobNO ListJob
----------------------------------------
1 0 1 1
2 1 2 1/2
3 1 3 1/3
4 0 4 4
5 4 5 4/5
6 5 6 4/5/6
You need to use a Recursive Common Table Expression.
There are many useful articles online.
Useful Links
Simple Talk: SQL Server CTE Basics
blog.sqlauthority: Recursive CTE
Here is a solution to your question:
CREATE TABLE #TEST
(
id int not null,
idparent int not null,
jobno int not null
);
INSERT INTO #Test VALUES
(1,0,1),
(2,1,2),
(3,1,3),
(4,0,4),
(5,4,5),
(6,5,6);
WITH CTE AS (
-- This is end of the recursion: Select items with no parent
SELECT id, idparent, jobno, CONVERT(VARCHAR(MAX),jobno) AS ListJob
FROM #Test
WHERE idParent = 0
UNION ALL
-- This is the recursive part: It joins to CTE
SELECT t.id, t.idparent, t.jobno, c.ListJob + '/' + CONVERT(VARCHAR(MAX),t.jobno) AS ListJob
FROM #Test t
INNER JOIN CTE c ON t.idParent = c.id
)
SELECT * FROM CTE
ORDER BY id;

How to get this below output from DUAL in oracle?

1 L R
1 1 1
1 1 2
1 1 3
1 2 1
1 2 2
1 2 3
1 3 1
1 3 2
1 3 3
Using this query but not able to get for L column
Select 1,level R
from DUAL
Connect by level <=3
You could do a Cartesian join in the row generator query you have to generate 3 rows. Thus, the Cartesian product would generate total 9 rows.
For example,
SQL> WITH DATA AS
2 ( SELECT LEVEL rn FROM dual CONNECT BY LEVEL <=3
3 )
4 SELECT 1, A.rn L, b.rn R FROM DATA A, DATA b
5 /
1 L R
---------- ---------- ----------
1 1 1
1 1 2
1 1 3
1 2 1
1 2 2
1 2 3
1 3 1
1 3 2
1 3 3
9 rows selected.
SQL>
select 1, L, R
from (Select level R
from DUAL
Connect by level <=3),
(Select level L
from DUAL
Connect by level <=3)
You might try something like this:
SELECT 1, CEIL(lvl/3) AS l
, ROW_NUMBER() OVER ( PARTITION BY CEIL(lvl/3) ORDER BY lvl ) AS r
FROM (
SELECT LEVEL AS lvl FROM dual
CONNECT BY LEVEL <= 9
);
The above avoids a cartesian join. See SQLFiddle here.

searche distinct table but return all columns

I need to query a table with 3 rows: id, ip and user_id
I want to return only the rows that have unique values of ip and user_id (not itself unique, but unique as a pair) eg:
id ip user_id
--------------------------------
1 1 2
2 1 2
3 1 2
4 2 5
5 2 5
6 2 8
7 2 8
8 3 10
9 3 11
the result must be:
id ip
------------
1 1
4 2
2 8
6 2
8 3
9 3
I'm using Oracle database.
select min(id),ip from table
group by ip,user_id
select id, ip
from the_table
join (
select min(id) as min_id
from the_table
group by ip, user_id
) t on t.min_id = the_table.id
order by id;
or:
select id, ip
from (
select id,
ip,
row_number() over (partition by ip_user_id order by id) as rn
from the_table
) t
where rn = 1
order by id;

MySQL - Selecting records based on maximum secondary ID

Here's part of my table:
id team_id log_id
1 12 1
2 12 1
3 12 1
4 12 1
5 1 2
6 1 2
7 1 3
8 1 3
What query would produce this output (so only the records with the highest log_id values are returned that correspond to team_id)?
id team_id log_id
1 12 1
2 12 1
3 12 1
4 12 1
7 1 3
8 1 3
SELECT *
FROM mytable t
WHERE log_id = (SELECT MAX(log_id) FROM mytable WHERE team_id = t.team_id)
SELECT id, team_id, log_id
FROM table1 t2
JOIN (SELECT team_id, MAX(log_id) max_log_id
FROM table1
GROUP BY team_id) t2 ON t1.team_id = t2.team_id
AND t1.log_id = t2.max_log_id