order different columns into one order? - sql

I have a table like this;
Student_Name1 mark1 Student_Name2 mark2
-------------- ------ --------------- --------
Kevin 77 Peter 78
Andrew 91 David 17
Scott 46 Bradley 28
How am i able to order mark1 and mark2 in the above table into descending order by including all the names and the points all together, like below?
Student_Name mark
-------------- ------
Andrew 91
Peter 78
Kevin 77
Scott 46
Bradley 28
David 17
I am using MSSQL Server 2008 R2

Use a UNION ALL:
Select Student_Name1 As Student_Name,
Mark1 As Mark
From YourTable
Union All
Select Student_Name2 As Student_Name,
Mark2 As Mark
From YourTable
Order By Mark Desc;

That's a strange table design but you can use UNION for this purpose like
select * from (
select Student_Name1 as Student_Name, mark1 as mark from student
union all
select Student_Name2 , mark2 from student ) xxx
order by mark desc;

Related

how to merge three rows into one row

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

Show mapping based on student access

There is a table which has following data:
student subject code
student1 maths 312
student1 physics 785
student2 english 900
student3 geography 317
I am trying to restrict access to each student in the table to view data specific to their chosen subject. But there is one restriction to show maths data to student2. Thereby both student1 and student2 both would be able to see maths data, and this mapping has to be done without altering the master data. So only while displaying the table, student2 should be mapped to both english and maths.
Thanks for the help here!
One option is to - as you said - temporarily use UNION set operator. Something like this:
SQL> WITH
2 test (student, subject, code)
3 AS
4 (SELECT 'student1', 'maths', 312 FROM DUAL
5 UNION ALL
6 SELECT 'student1', 'physics', 785 FROM DUAL
7 UNION ALL
8 SELECT 'student2', 'english', 900 FROM DUAL
9 UNION ALL
10 SELECT 'student3', 'geography', 317 FROM DUAL)
11 SELECT *
12 FROM test
13 WHERE student = '&&par_student'
14 -- add this to your query
15 UNION
16 SELECT 'student2', 'maths', NULL
17 FROM DUAL
18 WHERE '&&par_student' = 'student2';
Enter value for par_student: student1 --> student1 is OK, it has two subjects
STUDENT SUBJECT CODE
-------- --------- ----------
student1 maths 312
student1 physics 785
SQL> undefine par_student
SQL> /
Enter value for par_student: student2 --> for student2, UNION is used
STUDENT SUBJECT CODE
-------- --------- ----------
student2 english 900
student2 maths
SQL> undefine par_student
SQL> /
Enter value for par_student: student3 --> nothing new for student3
STUDENT SUBJECT CODE
-------- --------- ----------
student3 geography 317
SQL>
Depending on tool you use, parameter might look as this (in e.g. TOAD):
WHERE student = :par_student
or any other way parameters are used in that tool of yours.
Something like:
SELECT student, subject, code
FROM (
SELECT t.*,
COUNT(
CASE
WHEN student = :your_student
OR (:your_student, subject) IN (('student2', 'maths'))
THEN 1
END
) OVER (PARTITION BY subject) AS has_access
FROM table_name t
)
WHERE has_access > 0
Then, for the sample data:
CREATE TABLE table_name (student, subject, code) AS
SELECT 'student1', 'maths', 312 FROM DUAL UNION ALL
SELECT 'student1', 'physics', 785 FROM DUAL UNION ALL
SELECT 'student2', 'english', 900 FROM DUAL UNION ALL
SELECT 'student3', 'geography', 317 FROM DUAL;
If :your_student is student1 then the output is:
STUDENT
SUBJECT
CODE
student1
maths
312
student1
physics
785
and if :your_student is student2 then the output is:
STUDENT
SUBJECT
CODE
student2
english
900
student1
maths
312
db<>fiddle here

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);

Oracle: Combining similar names together

ItemNo Name Requested Qty
850045 MICHAEL 46 1045
850045 MICHAEL JACKSON 38 834
850045 LARRY SHEARIN 22 473
850045 Michael Jackson 11 233
850045 Larry 5 84
I have a table where Requester Name is not normalized. Michael and Michael Jack are the same person. Larry and Larry Shearin are also the same person. Is there a way to combine row data so that the Requested and Qty also sum up correctly? I was thinking there might be some sort of Oracle function or analytic that would do this...
ItemNo Name Requested Qty
850045 MICHAEL JACKSON 95 2112
850045 LARRY SHEARIN 27 557
There may be another way, but this should work using UPPER and matching any firstname (without spaces) to any fullname (with a space) -- if multiple full names match, you're results will be inaccurate.
SELECT T.ItemNo,
T.Name,
T.Requested + T2.Requested Requested,
T.Qty + T2.Qty Qty
FROM (
SELECT ItemNo, UPPER(Name) as Name, SUM(Requested) Requested, SUM(Qty) Qty
FROM YourTable
WHERE Name LIKE '% %'
GROUP BY ItemNo, UPPER(Name)
) T
JOIN (
SELECT ItemNo, UPPER(Name) as Name, SUM(Requested) Requested, SUM(Qty) Qty
FROM YourTable
WHERE Name NOT LIKE '% %'
GROUP BY ItemNo, UPPER(Name)
) T2 ON T.ItemNo = T2.ItemNo AND T.Name LIKE T2.Name||' %'
Here is the SQL Fiddle.
And here are the results:
ITEMNO NAME REQUESTED QTY
850045 MICHAEL JACKSON 95 2112
850045 LARRY SHEARIN 27 557
I assume you're total (32) for Larry was mistaken above (22 + 5)?
Hope this helps.

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