Denormalizing using query in Oracle - sql

I've a table like this:
STU_NAME SUBJECT MARKS
--------- --------- ------
1 ENGLISH 90
1 TAMIL 80
1 MATHS 70
2 MATHS 70
2 TAMIL 80
2 ENGLISH 95
And the result should be like below:
STU_NAME MATHS_MARK ENGLISH_MARK TAMIL_MARK TOTAL_MARKS
--------- ----------- ------------ ----------- -------------
1 70 90 80 240
2 70 95 80 245
Can we achieve this with a query?

I find that the easiest way is to use conditional aggregation:
select stu_name,
max(case when subject = 'MATHS' then Marks end) as Maths,
max(case when subject = 'ENGLISH' then Marks end) as English,
max(case when subject = 'TAMIL' then Marks end) as Tamil,
sum(Marks) as Total
from t
group by stu_name;

I got the same using PIVOT function.,
SELECT *
FROM (SELECT *
FROM x)
PIVOT (MAX(marks) FOR (SUBJECT) IN ('ENGLISH', 'MATHS', 'TAMIL'));
But, Still I'm facing few issues.,
whether it is possible to get sum(marks) while using PIVOT.
And getting subjects with respective marks without mentioning every subject(when we do know what are the subjects will be) in both(case,pivot).,?

Related

How to transform Table in hive

I have a table in Hive in below format.
std_id std_name sub_id sub_name marks
1 xxx 123 Eng 70
1 xxx 125 Maths 90
1 xxx 124 Science 80
I want a table in below format as output.
std_id std_name Eng Science Maths
1 xxx 70 80 90
how can i get the output with using Hive Query..
Use MAX ( CASE.. ) with GROUP BY
SELECT std_id
,std_name
,MAX(CASE
WHEN sub_name = 'Eng'
THEN marks
END) AS Eng
,MAX(CASE
WHEN sub_name = 'Science'
THEN marks
END) AS Science
,MAX(CASE
WHEN sub_name = 'Maths'
THEN marks
END) AS Maths
FROM t
GROUP BY std_id
,std_name;

sum of multiple fields in group by clause and create single row

I have a table like this.
Id Name Test Subject Marks
----------------------------
1 Alex 1 Maths 40
1 Alex 2 Maths 80
1 Alex 1 Sociology 55
1 Alex 2 Sociology 70
1 Alex 3 Sociology 60
2 Mark 1 Maths 30
2 Mark 2 Maths 60
2 Mark 1 Sociology 40
2 Mark 2 Sociology 50
2 Mark 3 Sociology 30
What I need is a group by on Id, Name, Subject and sum(Marks) in a single row, to give a result like:
Id Name Maths Sociology
-----------------------
1 Alex 120 185
2 Mark 90 120
I can get this as:
Id Name Marks
--------------
1 Alex 120
2 Mark 90
or:
Id Name Marks
-------------
1 Alex 185
2 Mark 120
I tried multiple options but I'm getting multiple rows for each ID.
The query below is not working:
select
Id, Name, Sum(Marks) where Subject = 'Maths' as Maths,Sum(Marks ) where Subject = 'Sociology' as Sociology
from
Table
group by
Id, Name;
I get this error:
"Error while compiling statement: FAILED: ParseException line 3:66 missing EOF at 'as' near ''Maths''
You are looking for PIVOT. Try :
create table #tbl(Id int, Name varchar(20), Test int, Subject varchar(20), Marks int)
insert into #tbl values
(1,'Alex',1,'Maths', 40 ),
(1,'Alex',2,'Maths', 80 ),
(1,'Alex',1,'Sociology', 55),
(1,'Alex',2,'Sociology', 70),
(1,'Alex',3,'Sociology', 60),
(2,'Mark',1,'Maths', 30 ),
(2,'Mark',2,'Maths', 60 ),
(2,'Mark',1,'Sociology', 40),
(2,'Mark',2,'Sociology', 50),
(2,'Mark',3,'Sociology', 30)
--select * from #tbl
SELECT ID,Name,Maths,Sociology
FROM(
SELECT ID, Name, Subject, Marks
FROM #tbl
) tbl
PIVOT(
SUM(Marks) FOR Subject IN (Maths, Sociology)
) piv
output:
ID Name Maths Sociology
----------- ---- ------------ -----------
1 Alex 120 185
2 Mark 90 120
You can use a case expression to effectively filter the values going into your sum:
select Id
,Name
,sum(case when Subject = 'Maths' then Marks else 0 end) as Maths
,sum(case when Subject = 'Sociology' then Marks else 0 end) as Sociology
from Table
group by Id
,Name;
If you are looking to do this across a lot of different subject values however, you will need to look at using pivot:
select Id
,[Name]
,[Maths]
,[Sociology]
from (select Id, [Name], [Subject], Marks from #t) as t
pivot(sum(Marks)
for [Subject] in(Maths,Sociology)
) as p;
Another solution using PIVOT operator:
SELECT
ID
,Name
,Maths
,Sociology
FROM(
SELECT
ID
,Name
,Subject
,Marks
FROM your_table
) tbl
PIVOT(
SUM(Marks) FOR Subject IN (Maths, Sociology)
) pvt
You can use below query :
select id,name,maths_marks,sociology_marks
from
(select id,name,test,subject,marks
from table)
pivot(sum(marks) for subject in ('Maths' as Maths_marks,'Sociology' as Sociology_marks);

SQL Teradata query

I have a table abc which have many records with columns col1,col2,col3,
dept | name | marks |
science abc 50
science cvv 21
science cvv 22
maths def 60
maths abc 21
maths def 62
maths ddd 90
I need to order by dept and name with ranking as ddd- 1, cvv - 2, abc -3, else 4 then need to find out maximum mark of an individual. Expected result is
dept | name | marks |
science cvv 22
science abc 50
maths ddd 90
maths abc 21
maths def 62
. How may I do it.?
SELECT
dept,
name,
MAX(marks) AS mark
FROM
yourTable
GROUP BY
dept,
name
ORDER BY
CASE WHEN name = 'ddd' THEN 1
name = 'cvv' THEN 2
name = 'abc' THEN 3
ELSE 4 END
Or, preferably, have another table that includes the sorting order.
SELECT
yourTable.dept,
yourTable.name,
MAX(yourTable.marks) AS mark
FROM
yourTable
INNER JOIN
anotherTable
ON yourTable.name = anotherTable.name
GROUP BY
yourTable.dept,
youtTable.name
ORDER BY
anotherTable.sortingOrder
This should work:
SELECT Dept, Name, MAX(marks) AS mark
FROM yourTable
GROUP BY Dept, Name
ORDER BY CASE WHEN Name = 'ddd' THEN 1
WHEN Name = 'cvv' THEN 2
WHEN Name = 'ABC' THEN 3
ELSE 4 END

Oracle 11G R2 SQL rows to columns

I have a table of bank staff information that looks like this:
branchNumber Position firstName lastName staffNumber
------------ -------- --------- -------- -----------
25 Manager john doe 11111
25 Secretary robert paulson 11112
25 Secretary cindy lu 11113
66 Manager tim timson 22223
66 Manager jacob jacobson 22224
66 Secretary henry henryson 22225
66 Supervisor paul paulerton 22226
I am actually done with this, but I completed the assignment using SQL common table expressions, and I can't use them in this project, I need them in this format.
branchNumber numOfManagers numOfSecretaries numOfSupervisors totalEmployees
------------ ------------- ---------------- ---------------- --------------
25 1 2 0 3
66 2 1 1 4
My issue is getting multiple columns with information from a row, I have this so far,
SELECT branchNumber, COUNT(*) AS numOfManagers
FROM Staff
WHERE position = 'Manager'
GROUP BY branchNumber, Position;
This outputs the correct information for numOfManagers, but making the next three columns eludes me without using CTE's. I tried sub selects too, with no luck. Anybody have any ideas?
You can use something like this:
select branchnumber,
sum(case when Position ='Manager' then 1 else 0 end) numofManagers,
sum(case when Position ='Secretary' then 1 else 0 end) numofSecretaries,
sum(case when Position ='Supervisor' then 1 else 0 end) numofSupervisors,
count(*) totalEmployees
from yourtable
group by branchnumber
See SQL Fiddle with Demo
Or you can use the PIVOT function:
select branchnumber,
'Manager', 'Secretary', 'Supervisor',
TotalEmployees
from
(
select t1.branchnumber,
t1.position,
t2.TotalEmployees
from yourtable t1
inner join
(
select branchnumber, count(*) TotalEmployees
from yourtable
group by branchnumber
) t2
on t1.branchnumber = t2.branchnumber
) x
pivot
(
count(position)
for position in ('Manager', 'Secretary', 'Supervisor')
) p;
See SQL Fiddle with Demo

Oracle 10g : SQL merging rows into single rows

I have a query that return below data structure :
Course Math Science Computer Chemistry
------ ---- ------- -------- ---------
CI101 98
CI101 87
CI101 78
CI101 102
CI101 23
CI101 56
CI101 89
CI101 45
How can have it be in the following structure using SQL:
Course Math Science Computer Chemistry
------ ---- ------- -------- ---------
CI101 98 78 23 45
CI101 87 102 56
CI101 89
Here is SQL I tried:
select course,
case
when subject = 'MATH' then
count
end as MATH,
case
when subject = 'SCIENCE' then
count
end as SCIENCE,
case
when subject = 'COMPUTER' then
count
end as COMPUTER,
case
when subject = 'CHEMISTRY' then
count
end as CHEMISTRY
from t_course
GROUP BY course, subject, count
Table Structure :
Course Subject Count
------ ------- -----
CI101 Math 98
....
Thanks ahead.
try this:
As I dont have Oracle and I didnt see any answer for this question, I have done this in sql server. This can be easily converted to Oracle sql.
I think, the only part requires conversion is ROW_NUMBER() over(order by [count]) as row_num which is basically to give a sequence number to each set
select CO.course,MA.count as 'MATH',SC.count as 'SCIENCE',CO.count as 'COMPUTER',CH.count as 'CHEMISTRY' from
(select course,[count],ROW_NUMBER() over(order by [count]) as row_num from t_course where subject = 'MATH')MA full outer join
(select course,[count],ROW_NUMBER() over(order by [count]) as row_num from t_course where subject = 'SCIENCE')SC on SC.row_num=MA.row_num full outer join
(select course,[count],ROW_NUMBER() over(order by [count]) as row_num from t_course where subject = 'COMPUTER')CO on CO.row_num=SC.row_num full outer join
(select course,[count],ROW_NUMBER() over(order by [count]) as row_num from t_course where subject = 'CHEMISTRY')CH on CO.row_num=CH.row_num
Please see the SQL fiddle Demo here