Given the tables student, mathematics_marks, science_marks
student
student_id (Primary Key) | smallint
student_name | varchar(30)
mathematics_marks
student_id (Primary Key) | smallint
score | float (5,2)
science_marks
student_id (Primary Key) | smallint
score | float (5,2)
A student is called as being a part of a symmetric pair if the marks obtained by that student in science is equal to the marks obtained by some other student in mathematics and the marks obtained in mathematics are the same as marks obtained by the other student in science.
Write a SQL query to print the name of the students who are a part of the symmetric pair. Order the output in order of student name.
with cte as (
select m.student_id, m.score as math_score, s.score as science_score
from mathematics_marks m inner join science_marks s
on s.student_id = m.student_id
)
select s1.student_name
from cte c1 inner join cte c2
on c2.student_id > c1.student_id and c2.math_score = c1.science_score and c1.math_score = c2.science_score
inner join student s1 on s1.student_id = c1.student_id and s1.student_id = c2.student_id
need to get the pair in two different rows?
EDITED:
answer to this
with cte as (
select m.student_id, m.score as math_score, s.score as science_score
from mathematics_marks m inner join science_marks s
on s.student_id = m.student_id
),
T as (select c1.student_id, c1.math_score, c1.science_score, s.student_name as name
from cte c1 inner join student s
on c1.student_id = s.student_id )
select t1.name from T t1 inner join T t2
on t1.math_score = t2.science_score and
t1.science_score = t2.math_score
order by t1.name
A properly designed schema would have a single table for student, subject, and mark. The first step then is to emulate that table, which could be as follows:
SELECT student_id
, 'mathematics' subject
, score
FROM mathematics_marks
UNION
SELECT student_id
, 'science'
, score
FROM science_marks
For further help, see: Why should I provide an MCRE for what seems to me to be a very simple SQL query?
It's always easy to answer if the post is accompanied by sample data and expected output . Are you looking for somthing like this
Select student.student_id
,maths.score maths_socer
,sci.score science_score
from
(
Select 1 student_id union all
Select 2 union all
Select 3
) student
Join
(
Select 1 student_id, 20 score union all
Select 2, 30 union all
Select 3, 40
) maths
on maths.student_id=student.student_id
Join
(
Select 1 student_id , 30 score union all
Select 2,20 union all
Select 3,40
) sci on sci.student_id !=student.student_id
Where sci.score = maths.score
Related
Given the tables student, mathematics_marks, science_marks
student
student_id (Primary Key) | smallint
student_name | varchar(30)
mathematics_marks
student_id (Primary Key) | smallint
score | float (5,2)
science_marks
student_id (Primary Key) | smallint
score | float (5,2)
A student is called as being a part of a symmetric pair if the marks obtained by that student in science is equal to the marks obtained by some other student in mathematics and the marks obtained in mathematics are the same as marks obtained by the other student in science.
I am trying to solve the above problem with the following query:
SELECT s.student_name
FROM student s
LEFT JOIN (mathematics_marks m CROSS JOIN science_marks sc)
ON (s.student_id = m.student_id AND m.student_id = sc.student_id)
WHERE EXISTS(SELECT * FROM mathematics_marks m
WHERE sc.score=m.score
AND m.score=sc.score)
ORDER BY student_name;
I am not getting correct output. Can anyone help me out where i am going wrong?
In a very simple way
select s.student_name 'student_name'
from student s
inner join mathematics_marks m
on m.student_id = s.student_id
inner join science_marks sc
on sc.student_id = s.student_id
where m.score in ( select score from science_marks ) and
sc.score in ( select score from mathematics_marks )
ORDER BY student_name;
I would do something like this:
SELECT s.student_name
FROM student s
LEFT JOIN mathematics_marks m ON m.student_id = s.student_id
LEFT JOIN science_marks sc ON sc.student_id = s.student_id
WHERE m.score IN (SELECT score FROM science_marks) OR sc.score IN (SELECT score FROM mathematics_marks)
Cross Join all students and then compare the marks for each student with other students.
select student1.student_name, student2.student_name
from (
select s1.student_id, s1.student_name, m1.score "m_score", sc1.score "sc_score"
from student s1
join mathematics_marks m1 on s1.student_id = m1.student_id
join science_marks sc1 on s1.student_id = sc1.student_id) student1,
(
select s2.student_id, s2.student_name, m2.score "m_score", sc2.score "sc_score"
from student s2
join mathematics_marks m2 on s2.student_id = m2.student_id
join science_marks sc2 on s2.student_id = sc2.student_id) student2
where student1.student_id<>student2.student_id
and student1.m_score = student2.sc_score
and student1.sc_score = student2.m_score;
For this requirement you need multiple joins of the 2 marks tables and finally to get the names of the students you need to join the table student twice:
select st1.student_name, st2.student_name
from mathematics_marks m1
inner join science_marks s1 on s1.student_id > m1.student_id and s1.score = m1.score
inner join mathematics_marks m2 on m2.student_id = s1.student_id
inner join science_marks s2 on s2.student_id < m2.student_id and s2.score = m2.score
inner join student st1 on st1.student_id = m1.student_id
inner join student st2 on st2.student_id = m2.student_id;
See the demo.
For simplicity and get all score under single table let's create a view.
create view student_marks as select mm.student_id,mm.score as m_score, sm.score as s_score
from mathematics_marks mm
inner join science_marks sm on mm.student_id=sm.student_id;
now we have all marks under single table.
so we need to do self join of above view and find students who satisfy the symmetric condition
select distinct s.*
from student_marks sm1
inner join student_marks sm2 on sm1.m_score=sm2.s_score and sm2.m_score=sm1.s_score
left join student s on s.student_id = sm1.student_id or s.student_id=sm2.student_id;
If you don't want to create view, you can simply replace student_marks with the view query.
I am trying to find the name of students where a symmetric pair exists. There are 3 tables:
**student**
student_id (Primary Key) | smallint
student_name | varchar(30)
**mathematics_marks**
student_id (Primary Key) | smallint
score | float (5,2)
**science_marks**
student_id (Primary Key) | smallint
score | float (5,2)
with Functions as (
select s.student_name as name, mm.score as math_score, sm.score as science_score
from student s
join mathematics_marks mm
on mm.student_id = s.student_id
join science_marks sm
on sm.student_id = s.student_id)
select t1.name
from Functions t1
join Functions t2
on t1.math_score = t2.science_score
and t1.science_score = t2.math_score
where t1.math_score < t1.science_score
Edit from your comment: A student is called as being a part of a symmetric pair if the marks obtained by that student in science is equal to the marks obtained by some other student in mathematics and the marks obtained in mathematics are the same as marks obtained by the other student in science.
Given the structure of the data, I would assume that students could have multiple marks in each subject. Otherwise, why store the values in separate tables?
To solve this problem, I would preaggregate the marks:
with mm as (
select student_id, group_concat(score order by score desc) as math_scores
from mathematics_marks
group by student_id
),
sm as (
select student_id, group_concat(score order by score desc) as science_scores
from science_marks
group by student_id
),
sms as (
select *
from mm join
sm
using (student_id)
)
select sms.student_id, sms2.student_id
from sms join
sms sms2
on sms.math_scores = sms2.science_scores and
sms.science_scores = sms2.math_scores and
sms.student_id < sms2.student_id;
This returns the matching ids. You need an additional join if you want to bring in the names.
Note: You have stored the values as floats. This is quite dangerous. You should be storing the values as decimal/numeric. Two values that look the same might actually be different.
This is how I would write the code for this requirement:
with cte as (
select m.student_id, m.score as math_score, s.score as science_score
from mathematics_marks m inner join science_marks s
on s.student_id = m.student_id
)
select s1.student_name, s2.student_name
from cte c1 inner join cte cte2
on c2.student_id > c1.student_id and c2.math_score = c1.science_score and c1.math_score = c2.science_score
inner join student s1 on s1.student_id = c1.student_id
inner join student s2 on s2.student_id = c2.student_id
Try this
select s.student_name as name, mm.score as math_score, sm.score as science_score
from student s
join mathematics_marks
mm
on mm.student_id
<s.student_id
join science_marks sm
on sm.student_id <s.student_id and
mm.math_score
=sm.science_score
The various tables and their columns are:
1)Course
course_id
course_name
duration
fee
2)Registration
course_id
stud_id
doj
3)Student
stud_id
first_name
last name
city
dob
I have tried:
SELECT
C.COURSE_ID,
C. COURSE_NAME,
COUNT(R.COURSE_ID) * FEES AS TOTAL_FEES
FROM
COURSE C,
REGISTRATION R,
WHERE
C.COURSE_ID = R.COURSE_ID
GROUP BY
R.COURSE_ID
SELECT c.cource_id, c.course_name, (totalNumberOfStudentPerCourse.totalNumberOfStudent * c.fee) as totalFee
FROM Course c
INNER JOIN
(SELECT r.course_id, COUNT(r.stud_id) as totalNumberOfStudent
FROM Registration r
GROUP BY r.course_id) totalNumberOfStudentPerCourse ON c.course_id = totalNumberOfStudentPerCourse.course_id
the subquery creates a totalNumberOfStudentPerCourse table that looks like this:
course_id totalNumberOfStudent
1 4
2 2
example:
course:
course_id course_name fee
1 math 300
2 english 200
registration:
course_id stud_id
1 1
1 2
1 3
1 4
2 5
2 6
result:
course_id course_name totalFee
1 math 1200
2 english 400
You can use a select on your group by query and then join it with the course table to use the rest of its fields.
SELECT aa.course_id, aa.course_name, aa.fee * _aa.total_registrations AS total_fees
FROM course AS aa
LEFT JOIN (
SELECT course_id, COUNT(*) as total_registrations
FROM registration
GROUP BY course_id
) AS _aa
ON aa.course_id = _aa.course_id
ORDER BY aa.course_name ASC
select c.courseid, c.coursename, c.fees * aa.tr as TOTALFEES
from course c
LEFT JOIN (
select courseid,COUNT(*) as tr
from registration
group by courseid
) aa
ON c.courseid = aa.courseid
order by c.courseid;
select courseid,coursename,(tsp_course.totalstd * c.fees) as TOTALFEES
from course c
inner join(select r.courseid,count(r.courseid) as totalstd
from registration r
group by r.courseid) tsp_course using(courseid)
order by courseid;
This is what you are looking for:
Select course.course_id,course.course_name,(count(reg.stud_id)*course.fee)
From Course course INNER JOIN Registration reg
ON course.course_id=reg.course_id
GROUP BY course.course_id,course.course_name,course.fee
I am stuck on how to get a student's minimum score from marks table and student info from student table.
EDIT: sorry for not mentioning, but i need result for user 1, st1
student
id name
1 st1
2 st2
marks
student_id course_name marks
1 C++ 55
1 OOP 65
1 AI 45 //need this lowest result for st1
2 C++ 82
2 STATS 74
2 OS 20 // lowest marks are these for st2 or overall
Edit forgot to enter name st1:
Desired Output:
id name course_name MinMarks
1 st1 AI 45
I tried this query but it gives wrong course_name (C++) 1st row's course name
SELECT s.id, s.name, m.course_name, MIN(m.marks) FROM student s
JOIN marks m
ON s.id = m.student_id
Where s.id = 1
Output:
id name course_name MinMarks
1 st1 C++ 45
You can use a subquery:
select *
from marks
where marks = (select min(marks) from marks)
or left join:
select m.*
from marks m
left join (select min(marks) as marks from marks) m_min on m.marks = m_min.marks
where m_min.marks is not null
It guarantees you that if there is more then one student with the minimum mark it displays all of them.
left join can possibly improve performance, you can check your execution plan to be sure.
P.S.: If you also need to retrieve name from student table (is not stated in your desired output) you can do the join operation you did in your query:
using subquery:
select m.student_id
, s.name
, m.course_name
, m.marks
from student s
join marks m on s.id = m.student_id
where m.marks = (select min(marks) from marks)
using left join:
select m.student_id
, s.name
, m.course_name
, m.marks
from student s
join marks m on s.id = m.student_id
left join (select min(marks) as marks from marks) m_min on m.marks = m_min.marks
where m_min.marks is not null
Edit
As it turns out, OP needs a minimum marks per student's id (for the id = 1), so :
select m.student_id
, s.name
, m.course_name
, m.marks
from student s
join marks m on s.id = m.student_id
left join (select student_id, min(marks) as marks from marks group by student_id) p on s.id = p.student_id and p.marks = m.marks
where s.id = 1 and p.student_id is not null
Try something like
select
s.id,
s.name,
m.course_name,
m.marks
from
student s
inner join marks m on
m.student_id = is.id
inner join (
select
student_id,
min(marks) min_mark
from
marks m
group by
student_id
) min_marks on
min_marks.student_id = s.id and
min_marks.student_id = m.student_id and
min_marks.min_mark = m.marks
If you are looking for only one student with the minimum mark, I would suggest order by and limit:
SELECT s.id, s.name, m.course_name, m.marks
FROM student s JOIN
marks m
ON s.id = m.user_id
ORDER BY m.marks ASC
LIMIT 1;
This solution will not work if you are looking for all students that have the same minimum mark.
try this:
Select s.id, s.name, m.course_name, m.marks From student s
right join marks m
on s.id = m.user_id where m.marks = MIN(m.marks);
SELECT s.id, s.name, m.course_name, m.marks
FROM marks m
JOIN student s
ON m.student_id = s.id
WHERE m.student_id=1 AND m.marks = (SELECT MIN(marks) FROM marks WHERE student_id=1)
I am having trouble trying to create a query to:
Select all the students who have not completed all peer review's for a particular week.
background: Each week, every student must peer review their peers in the same group.
Each group can be a different size, which is the problem I am having.
this is my current test data:
Table 1: peer review table
Table 2: student table.
This is my inital query, groups all the students based on the amount of peer review's they've made. I now need to to check if the count(*) is less than the size of the group for each student :
SELECT *
FROM peerreview
RIGHT JOIN student
ON student. studentID = peerreview.reviewer
WHERE week = 11
GROUP BY studentID
HAVING Count(*) < ????
Following query will return the student which has reviewed all the students in same group.
SELECT a.reviewer,
a.groupid
FROM (SELECT student2.studentID AS reviewer,
student1.groupid,
Count(*) AS cnt
FROM student student1
INNER JOIN peerreview
ON student1.studentID = peerreview.reviewee
INNER JOIN STUDENT STUDENT2
ON student2.studentID = peerreview.reviewer
WHERE student2.groupid = student2.groupid
AND peerreview.week = 11
GROUP BY student1.groupid,
student2.studentID) a
INNER JOIN (SELECT groupid,
Count(*) - 1 AS cnt
FROM student
GROUP BY groupid) b
ON a.groupid = b.groupid
AND a.cnt = b.cnt
See SqlFiddle
Select S.StudentId As Reviewer
, S1.StudentId As StudentYetToBeReviewed
, Weeks.WeekNum
From Student As S
Join Student As S1
On S1.GroupId = S.GroupId
And S1.StudentId <> S.StudentId
Cross Join (
Select 7 As WeekNum
Union All Select 11
) As Weeks
Where Not Exists (
Select 1
From PeerReview As P1
Where P1.reviewee = S1.StudentId
And P1.Week = Weeks.WeekNum
)
Order By WeekNum, reviewer
This provides you a list, by week, of the reviewer and the person they need to review. In the real solution, you would want to replace the Cross Join of weeks with a distinct list of weeks in which reviews should happen.
SQL Fiddle version
select distinct s1.*
from student s1 inner join student s2 on s1.groupId = s2.groupeId
left join peerreview pr on pr.revieweer = s1.studentId
and pr.reviewee = s2.studentId
where pr.Week = ? and pr.revieweer is null and s1.studentId <> s2.studentId