Students
ID FName Lname Status Major Code GPA Admitted Date
104 Donald Nento Sophomore 105 2.64 1-Jul-2015
Departments
Dept Code Dept Name College
105 Mathematics AS
These are the above tables... I am stuck on two questions:
List the college of the student with the highest GPA.
List Number of days elapsed since admission for each student.
Can anyone shed some light please?
List the college of the student with the highest GPA.
You can get all the college(s) with the maximum GPA without using a correlated sub-query like this:
SELECT College
FROM (
SELECT College,
RANK() OVER ( ORDER BY GPA DESC ) AS gpa_rank
FROM Students s
INNER JOIN
Departments d
ON ( s."Major Code" = d."Dept Code" )
)
WHERE gpa_rank = 1;
List Number of days elapsed since admission for each student.
SELECT ID,
FNAME,
LNAME,
FLOOR( SYSDATE - "Admitted Date" ) AS days_since_admission
FROM students;
You could use TRUNC(SYSDATE) - "Admitted Date" but if the admitted date has a time component then it will not be a round number.
(Note: it is unclear what your column names actually are. Your data shows them as case sensitive and with spaces but this is unusual as it is more usual to have case insensitive column names with underscores instead of spaces. I've used "" to match the column names used in your post but please adjust the names to whatever the actual values are.)
Here are some suggested queries. You'll need to adapt field names if they don't match. If you use double quotes the names are case sensitive, but if you have spaces in them, then you need to use double quotes:
List the college of the student with the highest GPA.
SELECT d."Dept Name"
FROM Departments d
INNER JOIN Students s
ON d."Dept Code" = s."Major Code"
WHERE s.GPA = (SELECT MAX(GPA) FROM Students);
Or, if you are not allowed to use INNER JOIN then:
SELECT d."Dept Name"
FROM Departments d,
Students s
WHERE d."Dept Code" = s."Major Code"
AND s.GPA = (SELECT MAX(GPA) FROM Students);
List Number of days elapsed since admission for each student.
SELECT s.*,
TRUNC(SYSDATE) - s.Admitted_Date AS days_since_admission
FROM Students s
Related
I'm working on this query:
SELECT s.studentname,
Avg(cs.exam_season_one
+ cs.exam_season_two
+ cs.degree_season_one
+ cs.degree_season_two ) / 4 AS average
FROM courses_student cs
join students s
ON s.student_id = cs.student_id
join SECTION se
ON s.sectionid = se.sectionid
WHERE cs.courses_id = 1
AND ( se.classes_id = 2
OR se.classes_id = 5 )
AND s.studentname LIKE 'm%'
GROUP BY s.studentname
until this moment everything works perfectly but I need to add a last condition and I dont know how.
I need to get the sudents with the same average
I mean only students with count(average) > 1 (idk if this is right)
anyone knows how to solve this problem in this query?
PS: I use oracle.
Edit:
The create tables statements and sample data are here:
http://sqlfiddle.com/#!4/ebf636
trying to explain the problem more because maybe I did it the wrong way the first time!
First, the average is the average of 4 columns
The output I expect is to get the names of the students who belong to class 2 or class 5 (classes_id = 2, classes_id = 5), also their name should start with M
I want to check their average in a specific course (course_id = 1)
and the last condition I'm asking about is that I want to get the students who only have the same average in this course.
for example:
if we have 4 students and the averages in the course are (60,70,80,80) then I want to get only the last 2 student names because they have the same average. hope it's clear now!
You appear to be asking for the students where the average of the averages of their exam and degree seasons 1 and 2 are greater than 1 for certain sections.
Without sample data and expected output to validate against, its difficult to answer but, for each student, you want to GROUP BY the primary key that uniquely identifies the student (otherwise you may aggregate two students with the same name together) and you only need to check if the section exists (rather than JOINing the section as that would create duplicate rows if there are multiple matching sections and skew the averages).
Then
if we have 4 students and the averages in the course are (60,70,80,80) then I want to get only the last 2 student names because they have the same average
You want to count how many students have the same average and then filter out those with unique averages:
SELECT studentname,
average
FROM (
SELECT a.*,
COUNT(*) OVER (PARTITION BY average) AS num_with_average
FROM (
SELECT MAX(s.studentname) AS studentname,
( Avg(cs.exam_season_one)
+ Avg(cs.exam_season_two)
+ Avg(cs.degree_season_one)
+ Avg(cs.degree_season_two) ) / 4 AS average
FROM courses_student cs
join students s
ON s.student_id = cs.student_id
WHERE cs.courses_id = 1
AND s.studentname LIKE 'm%'
AND EXISTS(
SELECT 1
FROM section se
WHERE s.sectionid = se.sectionid
AND se.classes_id IN (2, 5)
)
GROUP BY
s.student_id
) a
)
WHERE num_with_average > 1;
db<>fiddle here
I've recently started to learn tsql beyond basic inserts and selects, I have test database that I train on, and there is one query that I can't really get to work.
There are 3 tables used in that query, in the picture there are simplified fields and relations
I have 2 following queries - first one is simply displaying students and number of marks from each subject. Second is doing almost what I want to achive - shows students and maxiumum amount of marks they got, so ex.
subject1 - (marks) 1, 5, 3, 4 count - 4
subject2 - (marks) 5, 4, 5 - count - 3
Query shows 4 and from what I checked it returns correct results, but I want one more thing - just to show the name of the subject from which there is maximum amount of marks so in the example case - subject1
--Query 1--
SELECT s.Surname, subj.SubjectName, COUNT(m.Mark) as Marks_count
FROM marks m, students s, subjects subj
WHERE m.StudentId = s.StudentNumber and subj.SubjectNumber = m.SubjectId
GROUP BY s.Surname, subj.SubjectName
ORDER BY s.Surname
--Query 2--
SELECT query.Surname, MAX(Marks_count) as Maximum_marks_count FROM (SELECT s.Surname, subj.SubjectNumber, COUNT(m.Mark) as Marks_count
FROM marks m, students s, subjects subj
WHERE marks.StudentId = s.StudentNumber and subj.SubjectNumber = m.SubjectId
GROUP BY s.Surname, subj.SubjectName) as query
GROUP BY query.Surname
ORDER BY query.Surname
--Query 3 - not working as supposed--
SELECT query.Surname, query.SubjectName, MAX(Marks_count) as Maximum_marks_count FROM (SELECT s.Surname, subj.SubjectNumber, COUNT(m.Mark) as Marks_count
FROM marks m, students s, subjects subj
WHERE marks.StudentId = s.StudentNumber and subj.SubjectNumber = m.SubjectId
GROUP BY s.Surname, subj.SubjectName) as query
GROUP BY query.Surname, query.SubjectName
ORDER BY query.Surname
Part of the query 1 result
Part of the query 2 and unfortunately query 3 result
The problem is that when I add to the select statement subject name I got results as from query one - there is no more maximum amount of marks just students, subjects and amount of marks from each subject.
If someone could say what I'm missing, I will much appreciate :)
Here's a query that gets the highest mark per student, put it at the top of your sql file/batch and it will make another "table" you can join to your other tables to get the student name and the subject name:
WITH studentBest as
SELECT * FROM(
SELECT *, ROW_NUMBER() OVER(PARTITION BY studentid ORDER BY mark DESC) rown
FROM marks) a
WHERE rown = 1)
You use it like this (for example)
--the WITH bit goes above this line
SELECT *
FROM
studentBest sb
INNER JOIN
subject s
ON sb.subjectid = s.subjectnumber
Etc
That's also how you should be doing your joins
How does it work? Well.. it establishes an incrementing counter that restarts every time studentid changes (the partition clause) and the numberin goes in des ending mark order (the order by clause). An outer query selects only those rows with 1 in the row number, ie the top mark per student
Why can't I use group by?
You can, but you have to write a query that summarises the marks table into the top mark (max) per student and then you have to join that data back to the mark table to retrieve the subject and all in it's a lot more faff, often less efficient
What if there are two subjects with the same mark?
Use RANK instead of ROW_NUMBER if you want to see both
Edit in response to your comment:
An extension of the above method:
SELECT * FROM
(
SELECT *, ROW_NUMBER() OVER(PARTITION BY su, st ORDER BY c DESC) rn FROM
(
SELECT studentid st, subjectid su, count(*) c
FROM marks
GROUP BY st, su
) a
) b
INNER JOIN student stu on b.st = stu.studentnumber
INNER JOIN subject sub on b.su = sub.subjectnumber
WHERE
b.rn = 1
We count the marks by student/subject, then rownumber them in descending order of count per student-subject pair, then choose only the first row and join in the other wanted data
Ok thanks to Caius Jard, some other Stack's question and a little bit of experiments I managed to write working query, so this is how I did it.
First I created view from query1 and added one more column to it - studentId.
Then I wrote query which almost satisfied me. That question helped me a lot with that task: Question
SELECT marks.Surname,
marks.SubjectName,
marks.Marks_count,
ROW_NUMBER() OVER(PARTITION BY marks.Surname ORDER BY marks.Surname) as RowNum
FROM MarksAmountPerStudentAndSubject marks
INNER JOIN (SELECT MarksAmountPerStudentAndSubject.Id,
MAX(MarksAmountPerStudentAndSubject.Marks_count) as MaxAmount
FROM MarksAmountPerStudentAndSubject
GROUP BY MarksAmountPerStudentAndSubject.Id) m
ON m.Id = marks.Id and marks.Marks_count = m.MaxAmount
It gives following results
That's what I wanted to achieve with one exception - if students have the same amount of marks from multiple subjects it displays all of them - thats fine but I decided to restrict this to the first result for each student - I couldn't just simply put TOP(1)
there so I used similar solution that Caius Jard showed - ROW_NUMBER and window function - it gave me a chance to choose records that has row number equals to 1.
I created another view from this query and I could simply write the final one
SELECT marks.Surname, marks.SubjectName, marks.Marks_count
FROM StudentsMaxMarksAmount marks
WHERE marks.RowNum = 1
ORDER BY marks.Surname
With result
I am trying to tackle a problem but seem to be getting nowhere. I want to display Grade 12 students who scored below average for Maths then instead of displaying their average display their maths marks instead.
I am using msAccess and suspect the use of nested queries are necessary.The fields I am working with are first_name, last_name, grade (from 1 to 12) and Maths (containing maths marks)
I have this:
Select first_name,last_name,maths
FROM students
WHERE grade = 12
HAVING ROUND(AVG(maths),1)< maths;
Output:
Error:
You tried to execute a query that does not include the specified expression 'first_name' as part of an aggregate function
However, I do not know why it is throwing this error and it repeats like this even after removing the field from select which I don't want to do in the first place because I need to display it
To get the users who scored below the average, you can do a query similar to yours, but with a group by:
select s.student_id, avg(maths) as avg_maths
from students as s
where s.grade = 12
group by s.student_id
having avg(maths) < (select avg(maths) from students where grade = 12);
(Note: This assumes that you have an id for each student, rather than using the name.)
Next, you can get the original maths scores in various ways. One simple way uses in:
select first_name, last_name, maths
from students
where grade = 12 and
student_id in (select s.student_id, avg(s.maths) as avg_maths
from students as s
where s.grade = 12
group by s.student_id
having avg(maths) < (select avg(maths) from students where grade = 12)
);
I am working on PEOPLESOFT CMS . Students enroll in courses and
receive grades. Sometimes a student repeats a course and gets a
better grade. I need to calculate the GPA by using only the best
grade. So for each student that repeats courses, I have to determine
what the highest grade is.E.g. in 2nd semester he got 3 grade_point
but in in 4 semester he improved to 4.5 grad_point then query should
fetch 4.5 instead of 3 when we notify result for all 4 semester but
when we notify for upto 2nd semester its could return 3
grad_point.here i construct a sql which working fine in selection bt
when i make it view then i got a problem for handling it different
semester its always return max for 4th semester result bt in view
its missed the course upto 2 semester gpa here is query
SELECT DISTINCT A.institution
,A.acad_career
,A.emplid
,a.crse_id
,A.UNT_TAKEN
, a.acad_prog
,first_value(a.grade_points) OVER (PARTITION BY A.emplid
,a.crse_id
ORDER BY a.grade_points DESC) AS GPA
,first_value(a.strm) OVER (PARTITION BY A.emplid
,a.crse_id
ORDER BY a.grade_points DESC) AS strm
FROM ps_qau_maxgp_ugrd a
WHERE acad_career='UGRD'
AND Emplid LIKE '04091313014%'
AND Strm='1313'
ORDER BY A.institution ,A.acad_career ,A.emplid ,A.UNT_TAKEN , a.acad_prog
I believe you need to look at the date the grade was entered. For a given term and class-nbr, you should pull the greatest grade:
pseudo code:
select
max(date_entered)
group by
institution,
acad_career,
crse_id,
term,
class_nbr(if you have it)
The problem is that with the table you are using, i don't beleive is the actual enrollment table. I am only familiar with CS, so i would be looking at the ps_stdnt_enrl table or the ps_stdnt_car_term to get the accumulated data for a term.
Just use MAX and GROUP BY.
SELECT A.institution,
A.acad_career,
A.emplid,
a.crse_id,
A.unt_taken,
a.acad_prog,
Max(a.grade_points) GPA,
Max(a.strm) AS strm
FROM ps_qau_maxgp_ugrd a
WHERE acad_career = 'UGRD'
AND emplid LIKE '04091313014%'
AND strm = '1313'
GROUP BY A.institution,
A.acad_career,
A.emplid,
a.crse_id,
A.unt_taken,
a.acad_prog;
Here's the data table named "Salary_table" that i've created for this question:
So I want to find the number of employees in each salary bucket in each department. the buckets are
"<$100" "$100-$200" and ">$200"
The desired output is:
Below is my code for achieving this task:
select distinct(st.department) as "Department",
sb.salary_bucket as "salary range", count(*)
from Salary_table st
Left join (
select department, employee, case
when salary < 100 then "<$100"
when salary between 100 and 200 then "$100-$200"
else ">$200"
end
as salary_bucket
from Salary_table
) sb
on sb.employee = st.employee
group by st.department, sb.salary_bucket
order by st.department, sb.salary_bucket
;
but my output is a bit short of what im expecting:
There are TWO problems with my current output:
The buckets with 0 employees earning the salary in the bucket range are not listed; I want it to be listed with a value "0"
The salary bucket is NOT in the right order, even though I added in the statement "order by" but I think it's b/c its texts so can't really do that.
I would really appreciate some hints and pointers on how to fix/achieve these two issues I've addressed above. Thank you so much!
what i've tried
I tried use "left join" but output came out the same
I tried adding the "order by" clause but doesnt seem to work on text buckets
You are sort of on the right track, but the idea is a bit more complicated. Use a cross join to get all the rows -- the buckets and departments. Then use left join to bring in the matching information and finally group by for the aggregation:
select d.department, b.salary_bucket,
count(sb.department) as cnt
from (select '<$100' as salary_bucket union all
select '$100-$200' union all
select '>$200'
) b cross join
(select distinct department from salary_table
) d left join
(select department, employee,
(case when salary < 100 then '<$100'
when salary between 100 and 200 then '$100-$200'
else '>$200'
end) as salary_bucket
from Salary_table
) sb
on sb.department = d.department and
sb.salary_bucket = b.salary_bucket
group by d.department, b.salary_bucket;