Oracle SQL: update parent table column if all child table rows have specific value in a column. Update RANK of only those students who have 100 marks in all the subjects. If student has less than 100 marks in any subject, his RANK should not be updated.
I have a scenario where I have a parent table and a child table. The child table has a foreign key to parent table. I need to update parent table's status column when a column in child table rows have specific values. There are more than one child records for each parent, in some cases none. Is it possible to achieve this with Oracle SQL, without using PL/SQL. Is that possible, can some one explain how? In some case I have to update parent table row's column based on two columns of child table records.
My exact problem is like : I have two tables STUDENTS, MARKS. MARKS has a FK to STUDENTS named STUDENT_ID.MARKS has number of rows for a STUDENT record, depending on different subjects (MARKS has a FK to SUBJECTS), and has a column named MARKS_OBTAINED. I have to check that if MARKS_OBTAINED for one student for every subject (i.e. all his records in MARKS) have value 100, then update STUDENT table's column RANK to a value 'Merit'. This query:
update STUDENT
set RANK = 'Merit'
where exists ( select *
from MARKS
where MARKS.STUDENT_ID = STUDENT.ID
and MARKS.MARKS_OBTAINED = 100)
and not exists ( select *
from MARKS
where MARKS.STUDENT_ID = STUDENT.ID
and MARKS.MARKS_OBTAINED != 100)
updates all those student who have 100 marks in any subject. It does not exclude records which have non 100 marks. Because it passes rows for a STUDENT in MARKS where one record in MARKS has 100 MARKS_OBTAINED but other records have less than 100 marks, but since STUDENT obtained 100 marks in one subject, its RANK will also get updated. The requirement is that if any STUDENT records has a MARKS record with non 100 value in MARKS_OBTAINED column this STUDENT record should get excluded from the query.
Total rewrite
This is a complete rewrite to fit my example to the OQ's revised question. Unfortunately Manish has not actually run my original solution otherwise they would realise the following assertion is wrong:
Your solution returns all those student who have 100 marks in any subject. It does not exclude records which have non 100 marks.
Here are six students and their marks.
SQL> select * from student
2 /
ID RANK
---------- ----------
1 normal
2 normal
3 normal
4 normal
5 normal
6 normal
6 rows selected.
SQL> select * from marks
2 /
COURSE_ID STUDENT_ID MARK
---------- ---------- ----------
1 1 100
2 1 100
1 2 100
2 2 99
1 4 100
2 5 99
1 6 56
2 6 99
8 rows selected.
SQL>
Student #1 has two courses with marks of 100. Student #4 has just the one course but with with a mark of 100. Student #2 has a mark of 100 in one course but only 99 in the other course they have taken. None of the other students scored 100 in any course. Which students will be awarded a 'merit?
SQL> update student s
2 set s.rank = 'merit'
3 where exists ( select null
4 from marks m
5 where m.student_id = s.id
6 and m.mark = 100 )
7 and not exists ( select null
8 from marks m
9 where m.student_id = s.id
10 and m.mark != 100)
11 /
2 rows updated.
SQL>
SQL> select * from student
2 /
ID RANK
---------- ----------
1 merit
2 normal
3 normal
4 merit
5 normal
6 normal
6 rows selected.
SQL>
And lo! Only those students with 100 marks in all their courses have been updated. Never underestimate the power of an
AND
.
So the teaching is: an ounce of testing is worth sixteen tons of supposition.
0 comments:
Post a Comment