Select multiple records as multiple columns in SQL - 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

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;

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

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

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

How to select all duplicate rows except original one?

Let's say I have a table
CREATE TABLE names (
id SERIAL PRIMARY KEY,
name CHARACTER VARYING
);
with data
id name
-------------
1 John
2 John
3 John
4 Jane
5 Jane
6 Jane
I need to select all duplicate rows by name except the original one. So in this case I need the result to be this:
id name
-------------
2 John
3 John
5 Jane
6 Jane
How do I do that in Postgresql?
You can use ROW_NUMBER() to identify the 'original' records and filter them out. Here is a method using a cte:
with Nums AS (SELECT id,
name,
ROW_NUMBER() over (PARTITION BY name ORDER BY ID ASC) RN
FROM names)
SELECT *
FROM Nums
WHERE RN <> 1 --Filter out rows numbered 1, 'originals'
select * from names where not id in (select min(id) from names
group by name)

SQL COUNT(DISTINCT(field1)) GROUP BY MAX(filed2)

I have a table like
name num_try
John 2
John 1
Mike 3
Mike 2
Linda 2
And I want to know count distinct names group by MAX(num_try).
Desired result should look like
MAX(num_try) COUNT(DISTINCT(names))
2 2
3 1
Can you help me with this query?
select max_num_try, count(*) from
(
select name, max(num_try) as max_num_try
from table1
group by name
) a
group by max_num_try
order by max_num_try desc