I have this table
name | prof |grade
------------------------
yossi math 100
tami math 70
yossi phisic 100
tami phisic 100
oren math 100
oren phisic 80
dor history 70
The query should return name of student which have grade 100 in math and phisic
The correct unswer is yossi
I used the following
SELECT name FROM [dbo].[Class_grade]
where prof in ('math', 'phisic') and grade = 100
but it returns more names why?
what is the right query?
Thanks
select name
from Class_Grade
where grade = 100 and
prof in ('math', 'phisic')
group by name
having count(distinct prof) = 2
Group by name and filter out the rows using having. Make sure you count the distinct occurrences of prof. In this case it is 2 because you have 2 values in your in clause.
Earlier i misquoted the Question
You can use Group by caluse
SELECT name FROM [Class_grade]
where prof in ('math', 'phisic') and grade = 100
group by (name)
having count(1)=2
SQL FIDDLE
Try this
SELECT name FROM Class_grade
WHERE prof IN ('math', 'phisic') AND grade=100
GROUP BY name
HAVING COUNT(name) > 1
group by and make suure you get two rows
SELECT name
FROM Class_grade
WHERE prof in ('math', 'phisic') and grade = 100
GROUP BY name
HAVING count(*) = 2
http://www.sqlfiddle.com/#!3/9308c/6
EDIT
you can grab distinct grades if the same student can have more than one 100% in a subject
SELECT name
FROM (
SELECT DISTINCT name, prof, grade
FROM Class_grade
WHERE prof in ('math', 'phisic') and grade = 100
) class_grade
GROUP BY name
HAVING count(*) = 2
http://www.sqlfiddle.com/#!3/79fd0/11
The OP did not state a few details:
What is the primary key on the table (i.e. can multiple lines exist for the same student for the same subject)
What is the expected result when there are multiple students who match the criteria.
If we assume that one student can have multiple grades in the same subject, many of the other answers would be wrong with the HAVING COUNT(*) clauses. Mikael Eriksson's answer satisfies that assumption, and it is possibly more performant than my below solution (though functionally different a bit too):
SELECT DISTINCT name FROM [dbo].[Class_grade] cg1
WHERE EXISTS (
SELECT 1 FROM [dbo].[Class_grade] cg2
WHERE cg2.name = cg1.name
AND cg2.prof = 'math'
AND cg2.grade = 100)
AND EXISTS (
SELECT 1 FROM [dbo].[Class_grade] cg2
WHERE cg2.name = cg1.name
AND cg2.prof = 'phisic'
AND cg2.grade = 100)
AND NOT EXISTS (
SELECT 1 FROM [dbo].[Class_grade] cg2
WHERE cg2.name = cg1.name
AND cg2.prof in ('math','phisic')
AND cg2.grade < 100)
The difference in the above code is that it will only select students who have only grade = 100 for the math and phisic subjects, even if they could have more than one grade per subject. See here.
select Class_grade.name
from Class_grade
inner join Class_grade Class_grade2
on Class_grade.Name = Class_grade2.name
where Class_grade.Prof = 'math' and Class_grade.grade = 100
and Class_grade2.prof = 'phisic' and Class_grade2.grade = 100
group by Class_grade.Name
try not to use distinct, its a poor coding
Try this:
SELECT DISTINCT name FROM [dbo].[Class_grade] where prof in ('math', 'phisic') and grade = 100
This would work as well:
SELECT DISTINCT name FROM [dbo].[Class_grade] where (prof = 'math' and grade = 100) OR (prof = 'phisics' and grade = 100)
Related
I have a table similar to this (3 rows, 4 columns: id, name, gradeA, gradeB):
id name gradeA gradeB
------------------------------
1 David 59 78
2 Anna 66 92
3 David 22 89
I'm looking for a query that will give me 1 numeric property for the highest grade by in the whole table by condition.
for example:
What is the highest grade for any student named David?
The answer should be { maxGrade: 89 }
Note: grades are stored as varchar values and should be cast to numeric values for comparison
You need to combine max() with greatest()
select max(greatest(gradea::int, gradeb::int)) as max_grade
from the_table
where name = 'David';
If you need a JSON result (because you wrote: result should be {maxGrade: 89}), you can wrap that query and convert the row to JSON:
select to_jsonb(t)
from (
select max(greatest(gradea::int, gradeb::int)) as "maxGrade"
from the_table
where name = 'David'
) t;
I would recommend a lateral join:
select max(grade::int) as max_grade
from t cross join lateral
(values (gradea), (gradeb)) v(grade)
where name = 'David';
In particular, this works if any of the grades are NULL.
It can also easily be tweaked to get which grade is the maximum:
select v.*
from t cross join lateral
(values ('a', gradea), ('b', gradeb)) v(which, grade)
where name = 'David'
order by grade::int desc
limit 1
Try the below:
We shall achieve with GREATEST and MAX:
We can make use of GREATEST to return the large value between the columns grade A and grade B for every user record
And use MAX to return the maximum grade if more than user matches with the same name.
SELECT
MAX(GREATEST(gradeA::integer, gradeB::integer)) as maxGrade
FROM
"table_name"
WHERE
"table_name"."name" = 'David';
I have one student table which is given below
ROLL | STUDENT | SUBJECT | VERSION_ID |
1 A M 1
2 B M 2
3 C M 3
4 B S 1
5 D S 2
6 E E 1
7 F G 1
If there is atleast one record for SUBJECT='M' then retrieve latest record for SUBJECT 'M' based on version id.
ELSIF If there is atleast one record for SUBJECT='S' then retrieve latest record for SUBJECT 'S' based on version id.
ELSIF If there is atleast one record for SUBJECT='E' then retrieve latest record for SUBJECT 'E' based on version id.
Else DO NOT fetch any record.
Based on above condition I am trying to write a query or view which can satisfy all above condition and and give below output. Please suggest me possible solutions to get this.
Output
ROLL | STUDENT | SUBJECT | VERSION_ID |
3 C M 3
I have tried to get desired output using below query but I encountered with error. Please help me to solve this query with better performance.
SELECT * from ( IF EXISTS(select subject from STUDENT where SUBJECT='M') then
select * from STUDENT S1
inner join
(select S2.ROLL from STUDENT S2
where
S2.ROLL=(select S3.ROLL from STUDENT S3
where S3.SUBJECT='M'
and S3.VERSION_ID=(select MAX(S4.VERSION_ID) from STUDENT S4
GROUP BY S4.SUBJECT
HAVING S4.SUBJECT='M'))) S5
ON
S1.ROLL=S5.ROLL
ELSIF EXISTS(select subject from STUDENT where SUBJECT='S') then
select * from STUDENT S1
inner join
(select S2.ROLL from STUDENT S2
where
S2.ROLL=(select S3.ROLL from STUDENT S3
where S3.SUBJECT='S'
and S3.VERSION_ID=(select MAX(S4.VERSION_ID) from STUDENT S4
GROUP BY S4.SUBJECT
HAVING S4.SUBJECT='S'))) S5
ON
S1.ROLL=S5.ROLL
ELSIF EXISTS(select subject from STUDENT where SUBJECT='E') then
select * from STUDENT S1
inner join
(select S2.ROLL from STUDENT S2
where
S2.ROLL=(select S3.ROLL from STUDENT S3
where S3.SUBJECT='E'
and S3.VERSION_ID=(select MAX(S4.VERSION_ID) from STUDENT S4
GROUP BY S4.SUBJECT
HAVING S4.SUBJECT='E'))) S5
ON
S1.ROLL=S5.ROLL
ELSE
SELECT * FROM STUDENT WHERE 1=2);
TABLE CREATION:
Create table student (ROLL number,STUDENT varchar2(20),SUBJECT varchar2(20),VERSION_ID number );
Insert Data:
insert into STUDENT values(1,'A','M',1);
insert into STUDENT values(2,'B','M',2);
insert into STUDENT values(3,'C','M',3);
insert into STUDENT values(4,'B','S',1);
insert into STUDENT values(5,'D','S',2);
insert into STUDENT values(6,'E','E',1);
insert into STUDENT values(7,'F','G',1);
Thank You..
We can apply ROW_NUMBER to entire table, using the ordering logic you gave in your question. Subjects M, S, and E have priority, in that order, with the VERSION_ID breaking the tie. Rows with a subject not matching these three are assigned the lowest priority. Should there be no records with matching subjects, we filter out all records in the WHERE clause.
WITH cte AS (
SELECT ROLL, STUDENT, SUBJECT, VERSION_ID,
ROW_NUMBER() OVER (ORDER BY CASE WHEN SUBJECT = 'M' THEN 1
WHEN SUBJECT = 'S' THEN 2
WHEN SUBJECT = 'E' THEN 3
ELSE 4 END, VERSION_ID DESC END) rn
)
SELECT ROLL, STUDENT, SUBJECT, VERSION_ID
FROM cte
WHERE rn = 1 AND SUBJECT IN ('M', 'S', 'E')
You want right answer right? Try this :
SELECT TOP 1 #student.*
FROM student
JOIN (
SELECT MAX(VERSION_ID) VERSION_ID,SUBJECT
FROM student
WHERE SUBJECT = 'M'
GROUP BY SUBJECT
UNION ALL
SELECT MAX(VERSION_ID),SUBJECT
FROM student
WHERE SUBJECT = 'S'
GROUP BY SUBJECT
UNION ALL
SELECT MAX(VERSION_ID),SUBJECT
FROM student
WHERE SUBJECT = 'E'
GROUP BY SUBJECT
UNION ALL
SELECT MAX(VERSION_ID),SUBJECT
FROM student
WHERE SUBJECT = 'G'
GROUP BY SUBJECT
UNION ALL
SELECT NULL,NULL
) AS Dtls
ON (student.SUBJECT = Dtls.SUBJECT
AND student.VERSION_ID = Dtls.VERSION_ID)
I am relatively new to SQL and I may be over thinking it but given the following table.I want a list of all students that are enrolled in Chemistry but not Mathematics.So given the data I would have Student 1.
Student_ID Subject
1 Chemistry
2 Mathematics
2 Chemistry
3 History
Here's what I tried
SELECT Student_ID
FROM Student
WHERE (Subject = 'Chemistry') AND (Subject <> 'Mathematics')
Perhaps I need to group somewhere because rows and returned that exist for both criteria.
Here's one option using conditional aggregation:
select student_id
from student
group by student_id
having max(case when subject = 'Chemistry' then 1 end) = 1 and
max(case when subject = 'Mathematics' then 1 else 0 end) != 1
And here's another option using not exists:
select student_id
from student s
where subject = 'Chemistry' and not exists (
select 1
from student s2
where s.student_id = s2.student_id and st.subject = 'Mathematics'
)
You can use where and not in
select Student_ID
from Student
where Subject = 'Chemistry'
and Student_ID NOT IN ( select Student_ID from Student where subject ='Mathematics');
Please suggest a sql query to fetch the
"list of students and corresponding subject in which student has same score , if the student has same score in more than one subject"
eg.
Student Subject Score
John Science 80
John Maths 80
John English 80
John French 80
Peter Science 85
Peter Maths 70
Peter English 70
Peter French 70
Mathews French 70
Expected Result :
John Science
John Maths
John English
John French
Peter Maths
Peter English
Peter French
tried -
select person , subject where person in
( select person , score , count(score) group by person , score having count(score) > 1 )
but in this "Peter Science" appears , which is not required.
Please assist.
Thanks
Try:
select person , subject
from table t
join
( select person , score , count(score)
from table
group by person , score having count(score) > 1
) foo
on t.person = foo.person
where t.person = foo.person
and t.score = foo.score
The reason your query didn't work (aside from not including a table):
Your inner query was selecting the students and scores that match your criteria. But your outer query was selecting everything for all students who matched the criteria, which is why "peter science" was being included. So, you needed to limit the results in your outer query to only those that match all of your criteria.
You should tell us what RDBMS are you using. But this should work everywhere:
select
t.*
from <tableName> t
join (
select
student, score
from <tableName>
group by
student, score
having count(*)>1
) x
on t.student=x.student
and t.score=x.score
Btw you're missing FROM <tableName> in your query.
Try with this :
select student, subject
from Person
where student + cast(score as varchar(20)) in
(
select student + cast(score as varchar(20)) from Person group by student,score having count(score) > 1
)
You can achieve this goal self-joining table like in example:
SELECT
t.Student,
t.Subject,
t.Score
FROM Table1 AS t
JOIN
(
SELECT Student, Score FROM Table1 GROUP BY Student, Score HAVING COUNT(*) > 1
) AS t1 ON t.Student = t1.Student AND t.Score = t1.Score
Full example with test data and created table you can find here:
http://sqlfiddle.com/#!2/61f02/8
Student Table
SID Name
1 A
2 B
3 C
Marks Table
id mark subject
1 50 physics
2 40 biology
1 50 chemistry
3 30 mathematics
SELECT distinct(std.id),std.name,m.mark, row_number() over() as rownum FROM
student std JOIN marks m ON std.id=m.id AND m.mark=50
This result is 2 times A even after using disticnt . My expected result will have only one A. if i remove row_number() over() as rownum its working fine. Why this is happening ? how to resolve. AM using DB2!!
There are two rows in marks Table with id = 1 and mark = 50.. So you will get two rows in the output for each row in student table...
If you only want one, you have to do a group By
SELECT std.id, std.name, m.mark, row_number()
over() as rownum
FROM student std
JOIN marks m
ON m.id=std.id AND m.mark=50
Group By std.id, std.name, m.mark
Now that you've clarified your question as:
I want to find all students with a mark of 50 in at least one subject. I would use the query:
SELECT student.id, '50'
FROM student
WHERE EXISTS (SELECT 1 FROM marks WHERE marks.id = student.id AND marks.mark = 50)
This also gives you flexibility to change the criteria, e.g. at least one mark of 50 or less.
Similar to Charles answer, but you always want to put the predicate (mark=50) in the WHERE clause, so you're filtering before joining. If this is just homework it might not matter but you'll want to remember this if you ever hit any real data.
SELECT std.sid,
std.name,
m.mark,
row_number() over() AS rownum
FROM student std
JOIN marks m
ON std.sid=m.id
WHERE m.mark=50
GROUP BY std.sid, std.name, m.mark