how to change output of the sql query from 1 to 2
1:- user_id subject name marks
1001 maths 67
1001 pyhsics 78
1001 chemistry 87
1002 maths 89
1002 physics 56
1002 chemistry 76
2:- user_id maths physics chemistry
1001 67 78 87
1002 89 56 76
I'm expecting sql query
Use crosstab (pivot tables) to turn rows into columns:
SELECT *
FROM crosstab(
'SELECT user_id, subject_name, marks FROM t'
) AS ct(user_id int, maths int, physics int, chemistry int);
Another option, with a slightly different purpose, is to use conditional aggregates with FILTER:
SELECT
user_id,
SUM(marks) FILTER (WHERE subject_name = 'maths') AS maths,
SUM(marks) FILTER (WHERE subject_name = 'physics') AS physics,
SUM(marks) FILTER (WHERE subject_name = 'chemistry') AS chemistry
FROM t
GROUP BY user_id;
Demo: db<>fiddle
I think this is a basic question, but I couldn’t figure it out. I am new to this so please bear with me.
I am analyzing players data from the FIFA game, and I want to get a table with the highest rating of each individual player and the earliest age when that happened.
This is an example of the data:
id
name
position
rating
age
1
James
RW
70
20
1
James
RW
71
21
2
Frank
CB
73
23
2
Frank
CB
73
24
3
Miles
CM
75
27
3
Miles
CM
74
28
This is what the query should return:
id
name
position
rating
age
1
James
RW
71
21
2
Frank
CB
73
23
3
Miles
CM
75
27
I thought I could first get the highest overall for each player, and then do a JOIN to get the age, but that gives the other years a player had the same highest rating.
id
name
position
rating
age
1
James
RW
71
21
2
Frank
CB
73
23
2
Frank
CB
73
24
3
Miles
CM
75
27
Thank you,
One approach uses ROW_NUMBER with QUALIFY:
SELECT *
FROM yourTable
WHERE true
QUALIFY ROW_NUMBER() OVER (PARTITION BY id ORDER BY rating DESC, age) = 1;
Try this one (could be a bit faster):
with mytable as (
select 1 as id, "James" as name, "RW" as position, 70 as rating, 20 as age union all
select 1, "James", "RW", 71, 21 union all
select 2, "Frank", "CB", 73, 23 union all
select 2, "Frank", "CB", 73, 24 union all
select 3, "Miles", "CM", 75, 27 union all
select 3, "Miles", "CM", 74, 28
)
select array_agg(t order by rating desc, age asc limit 1)[OFFSET(0)].*,
from mytable as t
group by t.id
Try this one too if you want. I think it's what you need.
select p1.id,
p1.name,
p1.pos,
max(p1.rating),
p1.age
from players p1
join (select name, min(age) min_age
from players
group by 1) p2 on p1.name = p2.name and p1.age = p2.min_age
group by p1.id, p1.name, p1.pos, p1.age
This question already has answers here:
Split function equivalent in T-SQL?
(16 answers)
Closed 2 years ago.
I inherited a table that has these columns
ID, Name, Subjects
-- ---- --------
33 Mike Math,English,Physics
24 Paul Art,French,Med,English,Math
58 Sami Physics,Biology
22 Nora Math,English,Art
76 Mona Math,English,French,Med,Physics
39 Lila Physics
19 Dave Math,Biology,Physics
48 Jade English,French,Physics
82 Mark Med,Biology,Physics
23 Nina Biology,English,Physics
I am trying to break this into my structured table.
ID, Name, Subject
-- ---- --------
33 Mike Math
33 Mike English
33 Mike Physics
24 Paul Art
24 Paul French
24 Paul Med
24 Paul English
I tried with using STRING_SPLIT in the select statement
SELECT ID, Name, STRING_SPLIT(Subjects, ',') AS SUbject
FROM Students
but that did not work
'STRING_SPLIT' is not a recognized built-in function name.
How can I split these subjects into rows?
This script should generate the table and data
declare #Students as table (ID int, Name varchar(4), Subjects varchar(100))
INSERT INTO #Students (ID, Name, Subjects)
VALUES
(33,'Mike','Math,English,Physics'),
(24,'Paul','Art,French,Med,English,Math'),
(58,'Sami','Physics,Biology'),
(22,'Nora','Math,English,Art'),
(76,'Mona','Math,English,French,Med,Physics'),
(39,'Lila','Physics'),
(19,'Dave','Math,Biology,Physics'),
(48,'Jade','English,French,Physics'),
(82,'Mark','Med,Biology,Physics'),
(23,'Nina','Biology,English,Physics')
SELECT * FROM #Students
Response to suggested duplicate
Although this question was closed suggesting it similar to Split function equivalent in T-SQL? it is actually not.
That question is a simple like which a simple FROM string_split() can work for. I got the answer thanks to Gordon. I thought it might help other with the same issue. If you have a similar issue, you may find the answer down.
Just another option using a little XML
Example
Declare #YourTable Table ([ID] varchar(50),[Name] varchar(50),[Subjects] varchar(50))
Insert Into #YourTable Values
(33,'Mike','Math,English,Physics')
,(24,'Paul','Art,French,Med,English,Math')
,(58,'Sami','Physics,Biology')
,(22,'Nora','Math,English,Art')
,(76,'Mona','Math,English,French,Med,Physics')
,(39,'Lila','Physics')
,(19,'Dave','Math,Biology,Physics')
,(48,'Jade','English,French,Physics')
,(82,'Mark','Med,Biology,Physics')
,(23,'Nina','Biology,English,Physics')
Select A.ID
,A.Name
,B.*
From #YourTable A
Cross Apply (
Select RetSeq = row_number() over (order by 1/0)
,RetVal = ltrim(rtrim(B.i.value('(./text())[1]', 'varchar(max)')))
From ( values (cast('<x>' + replace((Select replace([Subjects],',','§§Split§§') as [*] For XML Path('')),'§§Split§§','</x><x>')+'</x>' as xml).query('.'))) as A(x)
Cross Apply x.nodes('x') AS B(i)
) B
Returns
ID Name RetSeq RetVal
33 Mike 1 Math
33 Mike 2 English
33 Mike 3 Physics
24 Paul 1 Art
24 Paul 2 French
24 Paul 3 Med
24 Paul 4 English
24 Paul 5 Math
58 Sami 1 Physics
58 Sami 2 Biology
22 Nora 1 Math
22 Nora 2 English
22 Nora 3 Art
76 Mona 1 Math
76 Mona 2 English
76 Mona 3 French
76 Mona 4 Med
76 Mona 5 Physics
39 Lila 1 Physics
19 Dave 1 Math
19 Dave 2 Biology
19 Dave 3 Physics
48 Jade 1 English
48 Jade 2 French
48 Jade 3 Physics
82 Mark 1 Med
82 Mark 2 Biology
82 Mark 3 Physics
23 Nina 1 Biology
23 Nina 2 English
23 Nina 3 Physics
You can use string_split() in the most recent versions of SQL Server:
SELECT ID, Name, ss.value as subject
FROM Students s CROSS APPLY
string_split(s.subjects, ',') ss;
You can also play with JSON or define your own split() function, although in older versions, I would just use a recursive CTE:
with cte as (
select s.id, convert(varchar(max), null) as subject, convert(varchar(max), subjects + ',') as rest
from students s
union all
select id, left(rest, charindex(',', rest) - 1),
stuff(rest, 1, charindex(',', rest), '')
from cte
where rest <> ''
)
select *
from cte
where subject is not null;
Here is a db<>fiddle.
Select name, Subject, Score from Class
Tables
name | Subject | Score
-----------------------
Ola maths 20
Ola pop 15
Ola eng 74
Dodo maths 21
Dodo pop 19
Dodo eng 54
Please any idea on how to make it display like this:
name | Subject | Score
-----------------------
Ola maths 20
pop 15
eng 74
Dodo maths 21
pop 19
eng 54
Please any assistant will be appreciated
if you absolutely have to do this in SQL:
with cte as
(
select rn=row_number() over (partition by name order by 1)
,*
from [table]
)
select n = case when rn=1 then name else '' end, Subject, Score
from cte
order by name,rn
But if you do this then you are losing the ability to use this data again.
As previous people have already comment, this might not be your best approach but the following query returns your expected result:
create table Class (Name varchar(10), Subject varchar(10), Score int)
insert into Class
values ('Ola', 'maths', 20),
('Ola', 'pop', 15),
('Ola', 'eng', 15),
('Dodo', 'maths', 20),
('Dodo', 'pop', 15),
('Dodo', 'eng', 15)
select
case when Row# = 1 then t.Name else null end,
Subject,
Score
from (
select
ROW_NUMBER() OVER(PARTITION BY Name ORDER BY Name ASC) AS Row#,
Name,
Subject,
Score
from Class) t
drop table Class