Home > database >  Oracle SQL nested subquery
Oracle SQL nested subquery

Time:09-15

Write a query to display list of subject names and minimum mark scored in 'Software Engineering' and 'Computer Programming' . Give an alias name as MIN_MARK for minimum mark column. Sort the result based on subject name in descending order. This is the db schema

 select subject_name , value as MIN_MARK from mark,subject where
 mark.subject_id = subject.subject_id and value in 
 (select min(value) from mark,subject where
 mark.subject_id = subject.subject_id and
 lower(subject_name) = 'computer engineering' and
 lower(subject_name) = 'software engineering')
 order by subject_name desc;

the required answer is

subject_name MIN_MARK
Computer Programming 65
Software Engineering 61

dont worry about contents of the db,help me get both the subject names in the output

CodePudding user response:

Your main error: The WHERE clause looks at one row at a time. There can't be a row in the table that matches both subjects:

where ...
and lower(subject_name) = 'computer engineering'
and lower(subject_name) = 'software engineering'

It must be

where ...
  and 
  (
      lower(subject_name) = 'computer engineering'
    or
      lower(subject_name) = 'software engineering'
  )

or simply

where ...
and lower(subject_name) in ('computer engineering', 'software engineering')

Then, you are making things more complicated than necessary. If you want one result row per subject_name, then GROUP BY subject_name.

The join syntax you are using has been deprecated for thirty years. Don't use it. If you are taught this syntax, quit that class, book or tutorial. Use explicit ANSI joins that got introduced in standard SQL in 1992.

select
  s.subject_name,
  min(m.value) as min_mark
from subject s
left outer join mark m on m.subject_id = s.subject_id
where lower(s.subject_name) in ('computer engineering', 'software engineering')
group by s.subject_name
order by s.subject_name desc;

I am using an outer join here for the case a subject does not have marks yet, but shall still be shown in the output. If this is not desired, change LEFT OUTER JOIN to INNER JOIN.

CodePudding user response:

The WITH clause is here just to generate some sample data and, as such, it is not a part of the answer. Sample data:

WITH
    subject AS
        (
            Select 1 "SUBJ_ID", 'Software Engineering'     "SUBJ_NAME", 'A1' "SUBJ_CODE", 11 "STAFF_ID" From Dual Union All
            Select 2 "SUBJ_ID", 'Computer Programming'     "SUBJ_NAME", 'A2' "SUBJ_CODE", 12 "STAFF_ID" From Dual Union All
            Select 3 "SUBJ_ID", 'Regenerative Cybernetics' "SUBJ_NAME", 'A3' "SUBJ_CODE", 13 "STAFF_ID" From Dual 
        ),
    mark AS
        (
            Select 61 "VALUE", 1 "SUBJ_ID", 101 "STUDENT_ID" From Dual Union All
            Select 65 "VALUE", 2 "SUBJ_ID", 101 "STUDENT_ID" From Dual Union All
            Select 74 "VALUE", 3 "SUBJ_ID", 101 "STUDENT_ID" From Dual Union ALL
            Select 72 "VALUE", 1 "SUBJ_ID", 102 "STUDENT_ID" From Dual Union All
            Select 69 "VALUE", 2 "SUBJ_ID", 102 "STUDENT_ID" From Dual Union All
            Select 66 "VALUE", 3 "SUBJ_ID", 102 "STUDENT_ID" From Dual Union ALL
            Select 91 "VALUE", 1 "SUBJ_ID", 103 "STUDENT_ID" From Dual Union All
            Select 67 "VALUE", 2 "SUBJ_ID", 103 "STUDENT_ID" From Dual Union All
            Select 70 "VALUE", 3 "SUBJ_ID", 103 "STUDENT_ID" From Dual 
        )

If you need just subject name and minimum value then you don't have to use nested query. Also, in your question, ordering should be on subject name descending but in your required answer the order is by minimum value descending.
Hope this could help you get it done:

Select 
    s.SUBJ_NAME "SUBJ_NAME",
    Min(m.VALUE) "MIN_MARK"
From 
    MARK m
Inner Join
    SUBJECT s ON(m.SUBJ_ID = s.SUBJ_ID)
Where
    s.SUBJ_NAME = 'Software Engineering' 
    OR 
    s.SUBJ_NAME = 'Computer Programming'
Group By
    s.SUBJ_NAME
Order By
    s.SUBJ_NAME DESC

... resulting as:

--  R e s u l t :
--  
--  SUBJ_NAME                  MIN_MARK
--  ------------------------ ----------
--  Software Engineering             61 
--  Computer Programming             65

Better way of filtering that would end up with the same result (if you know IDs) is:

Where
    s.SUBJ_ID IN(1, 2)

CodePudding user response:

I solved the above question

select subject_name,min(value) as MIN_MARK from mark,subject where
mark.subject_id = subject.subject_id and 
lower(subject_name) in ('computer programming' , 'software engineering')
group by subject_name
order by subject_name desc;

The output:

enter image description here

  • Related