Oracle SQL - Display rows as columns - Many to Many Relationship - sql

Good day! I need some guidance if I want to do is actually possible in Oracle SQL.
I have a table like this:
ID
Name
Code
999
Abby
1
999
Betty
1
999
Cass
2
999
Diane
2
999
Elly
2
999
Faye
3
999
Greg
4
999
Honey
4
999
Iman
4
999
Jam
4
999
Klade
5
And I want to achieve something like this:
ID
1
2
3
4
5
999
Abby
Cass
Faye
Greg
Klade
999
Betty
Dianne
Honey
999
Elly
Iman
999
Jam
`
I have tried joins, pivots, aggregates, but nothing seems to possibly work out (as far as I tried it.)
I even tried getting all the raw data and creating a new table but the only id I can reference them with is the ID.
Please help.
Any idea or references or resource to the right direction would be appreciated!
Thanks in advance!

Pivot is one option.
select *
from (select id, name, code,
row_number() over (partition by code order by name) rn
from test
)
pivot
(listagg(name, '') within group (order by null) val
for code in (1, 2, 3, 4, 5)
);
which results in
ID RN 1_VAL 2_VAL 3_VAL 4_VAL 5_VAL
---------- ---------- ---------- ---------- ---------- ---------- ----------
999 1 Abby Cass Faye Greg Klade
999 2 Betty Diane Honey
999 3 Elly Iman
999 4 Jam

The key idea is to use row_number(), but I prefer conditional aggregation:
select code,
max(case when code = 1 then name end) as code_1,
max(case when code = 2 then name end) as code_2,
max(case when code = 3 then name end) as code_3,
max(case when code = 4 then name end) as code_4,
max(case when code = 5 then name end) as code_5
from (select t.*,
row_number() over (partition by id, code order by name) as seqnum
from t
)
group by id, seqnum

Related

query a table with multiple rows for same id, into single data row in results

I have a few tables like this where a person has multiple data rows. The IDs are sequential but do not always start at 1. Is there a way to have the results come out in a single data row for each person. I have a few tables like this and I ultimately would like to join them via CLIENT_ID, but I'm a bit stumped. Is this possible?
Using oracle sql.
CLIENT_ID
NAME
ID
ID_DESCRIPTION
5
joe
1
apple
5
joe
5
orange
68
brian
2
orange
68
brian
6
mango
68
brian
10
lemon
12
katie
3
watermelon
where the results look like this
CLIENT_ID
NAME
ID1
ID1_DESCRIPTION
ID2
ID2_DESCRIPTION
ID3
ID3_DESCRIPTION
5
joe
1
apple
5
orange
68
brian
2
orange
6
mango
10
lemon
12
katie
3
watermelon
If Pivot ist not available, this should do it:
Select
Client_id,
sum(case when id_description='apple' then 1 else 0 end) as Apples,
sum(case when id_description='orange' then 1 else 0 end) as Oranges...
[]etc.
from
t
group by Client_ID
Might need some minor tweaking as I wrote this just off the top of my head, but something like this should work. Will say this doesn't account for more than 3 rows per CLIENT_ID. For that, would need to do a dynamic pivot (plenty of online articles on this topic).
Pivoting Based on Order of Items
WITH cte_RowNum AS (
SELECT ROW_NUMBER() OVER (PARTITION BY CLIENT_ID ORDER BY ID) AS RowNum
,*
FROM YourTable
)
SELECT CLIENT_ID
,MAX(CASE WHEN RowNum = 1 THEN ID END) AS ID1
,MAX(CASE WHEN RowNum = 1 THEN [Description] END) AS ID1_DESCRIPTION
,MAX(CASE WHEN RowNum = 2 THEN ID END) AS ID2
,MAX(CASE WHEN RowNum = 2 THEN [Description] END) AS ID2_DESCRIPTION
,MAX(CASE WHEN RowNum = 3 THEN ID END) AS ID3
,MAX(CASE WHEN RowNum = 3 THEN [Description] END) AS ID3_DESCRIPTION
FROM cte_RowNum
GROUP BY CLIENT_ID;

How to delete records with lower version in big query?

Lets say my table contains the following data
id
name
version
1
Rahul
1
1
Rahul
2
2
John
1
3
Mike
1
2
John
2
4
Rubel
1
5
David
1
1
Rahul
3
I need to filter the duplicate records with lower version. How can this be done?
The output essentially should be
id
name
version
1
Rahul
3
2
John
2
3
Mike
1
4
Rubel
1
5
David
1
For this dataset, aggregation seems sufficient:
select id, name, max(version) as max_version
from mytable
group by id, name
You can use not exists as follows:
select id, name, version
from your_table t
Where not exists
(Select 1 from your_table tt
Where tt.id = t.id and tt.version > t.version)
Or you can use analytical function row_number as follows:
Select id, name, version from
(select t.*,
Row_number() over (partition by id order by version desc) as rn
from your_table t) t
Where rn = 1

I'm trying to achieve below result output

can we get the below desired table by using PIVOT or something. I'm trying to convert below table to the desired output like below.
Data Set:
question_id element_id
1 john
1 bran
1 o_siera
2 brook
2 joseph
2 o_daniel
2 o_cody
3 derick
3 james
3 sophia
3 o_sandra
3 o_ashley
Desired Result:
question_id element_id element
1 john o_siera
1 bran o_siera
2 brook o_daniel
2 joseph o_daniel
3 derick o_sandra
3 james o_sandra
3 sophia o_sandra
OR
OR can we achieve it in this way
question_id element_id element
1 john o_siera
1 bran
2 brook o_daniel,o_cody
2 joseph
3 derick o_sandra, o_ashley
3 james
3 sophia
Its not an ideal data model. Something like this should work except when a value that begins with 'o_%' is an element_id and not an element.
This was not tested.
select t1.question_id
,case when t1.element_id not like 'o_%' then t1.element_id else '' end element_id
,case when t2.element_id like 'o_%' then t2.element_id else '' end element
from table t1
join table t2 on t1.question_id=t2.question_id
I would suggest:
select t.*, max_o
from (select t.*,
max(case when element_id like 'o\_%' then element_id end) over (partition by question_id) as max_o
from t
) t
where element_id not like 'o\_%';

Edit 2 rows into 2 columns in a single result SQL

I have the following table:
WorkID WorkDesc
--------------------
1 ABCD
2 DEFG
3 HIJK
then I've the following table as the detail of table one:
WorkDetailID WorkID WorkDetailDesc
-----------------------------------------
1 1 001
2 1 002
3 2 006
4 2 007
5 3 015
Each WorkID is always have maximum 2 records and minimum is 1.
I want to have the following result:
WorkID WorkDesc WorkDetailID1 WorkDetailID2
-------------------------------------------------------
1 ABCD 1 2
2 DEFG 3 4
3 HIJK 5 null
Does anyone have an idea how to do that?
Thank you.
You can use pivot. I prefer conditional aggregation. In either case, you need a column for the pivoting. row_number() to the rescue:
select t1.workid, t1.workdesc,
max(case when t2.seqnum = 1 then t2.workdetailid end) as workdetailid1,
max(case when t2.seqnum = 2 then t2.workdetailid end) as workdetailid2
from t1 join
(select t2.*,
row_number() over (partition by t2.workid order by t2.workdetailid) as seqnum
from t2
) t2
on t1.workid = t2.workid
group by t1.workid, t1.workdesc

Select multiple records as multiple columns in SQL

I have a table that look like this:
ID Name
-------
1 John
1 Mary
1 Jane
2 John
2 Mary
3 Jane
Knowing that every ID can only contain up to three names, I want to use a SELECT statement to turn this into the following:
ID Name1 Name2 Name3
--------------------
1 John Mary Jane
2 John Mary
3 Jane
Is there a way to do this in SQL?
If you know that there are at most three names, you can do this using conditional aggregation:
select id,
max(case when seqnum = 1 then name end) as name1,
max(case when seqnum = 2 then name end) as name2,
max(case when seqnum = 3 then name end) as name3
from (select t.*, row_number() over (partition by id order by name) as seqnum
from table t
) t
group by id;
With Oracle, you can use the PIVOT feature.
However, you'll need to RANK your rows first, over id-name pairs, and then you can do the pivot directive for (literally) the rank you just generated.
Pages to read:
http://www.oracle.com/technetwork/articles/sql/11g-pivot-097235.html
http://www.oracle-developer.net/display.php?id=506