I'm sorry if this is a duplicate question, but I had no idea which search keywords to use (that's why the question is vague as well)
I have a table like this
Parent_ID Parent_item Child_Item
1 A B
1 A C
2 H I
2 H J
2 H K
And I would like to have the results in the following format:
Parent_ID Parent_or_Child
1 A
1 B
1 C
2 H
2 I
2 J
2 K
How can this be done?
Thanks!
You need to unpivot the data, use UNION
select Parent_ID,Parent_item
from yourtable
Union
select Parent_ID,Child_Item
from yourtable
You need to unpivot the data, and it seems you don't want duplicates so you need to select distinct. In Oracle 11.1 or above, you can use the UNPIVOT operator - the advantage is that the base table will be read just once.
You can add an order by clause if you need it; I didn't, so the rows in the output are in arbitrary order (if you compare to your "desired output").
with
test_data ( Parent_ID, Parent_item, Child_Item ) as (
select 1, 'A', 'B' from dual union all
select 1, 'A', 'C' from dual union all
select 2, 'H', 'I' from dual union all
select 2, 'H', 'J' from dual union all
select 2, 'H', 'K' from dual
)
-- End of test data (NOT part of the query).
-- SQL query begins BELOW THIS LINE.
select distinct parent_id, parent_or_child
from test_data
unpivot (parent_or_child
for col in (parent_item as 'parent_item', child_item as 'child_item'))
;
PARENT_ID PARENT_OR_CHILD
---------- ---------------
2 I
1 A
1 B
1 C
2 H
2 J
2 K
7 rows selected.
Related
I have this table structure
ID,SUPPLIER_GROUP1,SUPPLIER1,SUPPLIER_GROUP2,SUPPLIER2.
i want to unpivot and get
ID,SUPPLIER_GROUP,SUPPLIER,TYPE
so each supplier_group and supplier values come to the appropriate column and in TYPE column will be either 1 or 2 to see if the SUPPLIER_GROUP and SUPPLIER value was supplier1 or supplier2 .
Use UNPIVOT with multiple column groups:
SELECT *
FROM table_name
UNPIVOT (
(supplier_group, supplier) FOR type IN (
(supplier_group1, supplier1) AS 1,
(supplier_group2, supplier2) AS 2
)
);
Which, for the sample data:
CREATE TABLE table_name (ID,SUPPLIER_GROUP1,SUPPLIER1,SUPPLIER_GROUP2,SUPPLIER2) AS
SELECT 1, 'sg1.1', 's1.1', 'sg2.1', 's2.1' FROM DUAL UNION ALL
SELECT 2, 'sg1.2', 's1.2', 'sg2.2', 's2.2' FROM DUAL UNION ALL
SELECT 3, 'sg1.3', 's1.3', 'sg2.3', 's2.3' FROM DUAL
Outputs:
ID
TYPE
SUPPLIER_GROUP
SUPPLIER
1
1
sg1.1
s1.1
1
2
sg2.1
s2.1
2
1
sg1.2
s1.2
2
2
sg2.2
s2.2
3
1
sg1.3
s1.3
3
2
sg2.3
s2.3
db<>fiddle here
This is the table.
Id. Name
1 A
1 A
2 B
2 C
1 A
2 B
2 D
The output should be
Id. Name
1 A
2 B
2 C
2 D
please try
Select distinct id, name
from <name of you table>
order by name
Check this link.
Sample data:
create table demo (id, name) as
select 1, 'A' from dual union all
select 1, 'A' from dual union all
select 2, 'B' from dual union all
select 2, 'C' from dual union all
select 1, 'A' from dual union all
select 2, 'B' from dual union all
select 2, 'D' from dual;
select * from demo order by 1,2;
ID NAME
---------- ------------------------------
1 A
1 A
1 A
2 B
2 B
2 C
2 D
7 rows selected
Delete all but the first row in each (id, name) group:
delete demo where rowid in
( select lag(rowid) over (partition by id, name order by null) from demo );
3 rows deleted
select * from demo order by 1,2
ID N
---------- -
1 A
2 B
2 C
2 D
4 rows selected.
i have a table called abc
columns and data are like:-
a b c
------------
ab 1 2
bc 2 3
cd 3 4
de 4 5
maybe there is data for cyclic like-
ef 5 1
i want output as:-
A b d
------------
ab 1 5/4/3/2/1
bc 2 5/4/3/2
cd 3 5/4/3
de 4 5/4
ef 5 5
please help me out find a query to retrive data like this
with
my_data(a,b,c) AS (
select 'ab', 1, 2 from dual union all
select 'bc', 2, 3 from dual union all
select 'cd', 3, 4 from dual union all
select 'de', 4, 5 from dual union all
select 'ea', 5, 1 from dual
)
select a, b, sys_connect_by_path(b, '/') d
from my_data t
connect by nocycle c = prior b
start with c = 1
order by a;
You may use listagg with select level from dual connect by level <= ? statement, and do not need column c( and column a is only needed for output ), as in the following routine :
create table tab( a varchar2(2), b int );
insert all
into tab values('ab',1)
into tab values('bc',2)
into tab values('cd',3)
into tab values('de',4)
into tab values('ef',5)
select * from dual;
select a, b,
( select listagg(6-level,'/') within group (order by level)
from dual
connect by level <= 6-b ) as d
from tab t;
SQL Fiddle Demo
You may use a recursive CTE with a CYCLE clause to avoid cyclic data
WITH cte(a, b, c, d) AS
( SELECT a,
b,
c,
to_char(b) AS d
FROM abc
WHERE c = 1
UNION ALL SELECT t.a,
t.b,
t.c,
cte.d ||'/'||t.b
FROM abc t
JOIN cte ON (cte.b = t.c) )
CYCLE b SET CYCLE TO 1 DEFAULT 0
SELECT a,
b,
d
FROM cte
WHERE CYCLE = 0
ORDER BY b ;
Demo
I have a lot of SQL experience but this one is beyond my understanding. I have a table such as:
ID NAME PARENT_ID
1 A 0
2 B 1
3 C 1
4 D 0
5 E 4
6 F 4
7 G 4
And I need to write a single SQL statement that will return all the parents and their children in a single row:
ID PARENT CHILD_1 CHILD_2 CHILD_3 ... CHILD_N
1 A B C
4 D E F G
I do not know how many children each parent has before hand - it is variable.
Is there anyway to do this in a single SQL statement?
Thanks.
You can use some of the very cool "dynamic pivot" PL/SQL solutions out there (which I don't recommend for production code -- they work 99% but fail for some odd-ball cases, in my experience).
Otherwise, you need to tell Oracle ahead of time which columns you expect your SQL to output. That means, you can only do what you're looking to do if you implement a hard cap on the maximum number of child columns you'll include.
If you can live with having to do that, then this should work. I took some guesses about how you would want it to work if your data had a hierarchy with multiple levels. (Take a look at row "H" in the sample data and think about how you would want that displayed.)
WITH d AS (
SELECT 1 id, 'A' name, 0 parent_id
FROM DUAL UNION ALL
SELECT 2, 'B', 1
FROM DUAL UNION ALL
SELECT 3, 'C', 1
FROM DUAL UNION ALL
SELECT 4, 'D', 0
FROM DUAL UNION ALL
SELECT 5, 'E', 4
FROM DUAL UNION ALL
SELECT 6, 'F', 4
FROM DUAL UNION ALL
SELECT 7, 'G', 4
FROM DUAL UNION ALL
SELECT 8, 'H', 7
FROM DUAL
),
h as (
select prior d.name parent,
level lvl,
case when level = 1 then null else d.name end child_name,
case when level = 1 then null else row_number() over ( partition by prior d.name, level order by d.name) end child_Number
from d
connect by parent_id = prior id
start with parent_id = 0 )
select * from h
pivot ( max(child_name) for (child_number) in (1 AS "CHILD_1",2 AS "CHILD_2",3 AS "CHILD_3",4 AS "CHILD_4",5 AS "CHILD_5") )
where lvl > 1
order by parent;
I have some one-many normalized data that looks like this.
a | x
a | y
a | z
b | i
b | j
b | k
What query will return the data such that the "many" side is represented as a CSV string?
a | x,y,z
b | i,j,k
Mark,
If you are on version 11gR2, and who isn't :-), then you can use listagg
SQL> create table t (col1,col2)
2 as
3 select 'a', 'x' from dual union all
4 select 'a', 'y' from dual union all
5 select 'a', 'z' from dual union all
6 select 'b', 'i' from dual union all
7 select 'b', 'j' from dual union all
8 select 'b', 'k' from dual
9 /
Tabel is aangemaakt.
SQL> select col1
2 , listagg(col2,',') within group (order by col2) col2s
3 from t
4 group by col1
5 /
COL1 COL2S
----- ----------
a x,y,z
b i,j,k
2 rijen zijn geselecteerd.
If your version is not 11gR2, but higher than 10gR1, then I recommend using the model clause for this, as written here: http://rwijk.blogspot.com/2008/05/string-aggregation-with-model-clause.html
If lower than 10, then you can see several techniques in rexem's link to the oracle-base page, or in the link to the OTN-thread in the blogpost mentioned above.
Regards,
Rob.