Oracle viewing highest record - sql

I have a Module and Students table as well as a linker table called Results. I am trying to display only one record of the student with the highest result for the specific module but i cannot get it to work. Here is my sql syntax so far:
SELECT S.ST_FNAME, S.ST_LNAME, M.MOD_NAME, R.RES_GRADE
FROM STUDENT S, MODULE M, RESULTS R
WHERE S.ST_ID=R.ST_ID AND M.MOD_ID=R.MOD_ID
AND M.MOD_ID=503;
At the moment it displays all the students and their results for the specific module.
help would be appreciated

To get a single value for a group of rows, use GROUP BY (in your case, with MAX to get the maximum):
SELECT
S.ST_FNAME,
S.ST_LNAME,
M.MOD_NAME,
max(R.RES_GRADE) as max_grade
FROM STUDENT S
JOIN RESULTS R on S.ST_ID = R.ST_ID
JOIN MODULE M on R.MOD_ID = M.MOD_ID
WHERE M.MOD_ID=503
GROUP BY s.st_fname, s.st_lname, m.mod_name;
I've also converted your old-style joins to ANSI-style joins - using ANSI style is preferred by most people nowadays.
SQL Fiddle

Related

Why can't I get GROUP BY to work in my LEFT JOIN in Access

I'm trying to populate a combobox from two tables in Access (2007-2016 file format).
I have two tables:
tblSurveyStatus
SurveyID
SurveyStatus
1
Y
2
N
3
N/A
tblWorkOrder
WONumber
SurveyedID
WO2101
1
WO2102
1
WO2103
2
WO2104
3
WO2105
2
WO2106
{Empty}
WO2107
{Empty}
Desired Result:
WONumber(this col will get hidden)
SurveyStatus
WO2101
Y
WO2103
N
WO2104
N/A
This query works in the datasource for the combobox without using GROUP BY:
SELECT SurveyedID, SurveyStatus
FROM [tblWorkOrders] a
LEFT JOIN (
SELECT SurveyID, SurveyStatus
FROM [tblSurveyStatus]
) b
ON a.SurveyedID = b.SurveyID
ORDER BY b.SurveyID
The problem with this query is that it returns duplicates (Y,Y,N,N,N/A).
So I introduced the GROUP BY like this:
SELECT SurveyedID, SurveyStatus
FROM [tblWorkOrders] a
LEFT JOIN (
SELECT SurveyID, SurveyStatus
FROM [tblSurveyStatus]
) b
ON a.SurveyedID = b.SurveyID
GROUP BY a.SurveyStatus ORDER BY b.SurveyID
This causes an error message "Your query does not include the specified expression 'SurveyedID' as part of an aggregate function." So, I put MIN(SurveyedID) and the error message moves to the next field so I keep putting MIN() in the SQL until finally it works but, I get an input box asking for the "SurveyStatus" then another one asking for the "SurveyID".
I have spent three solid days researching, reading threads on this website and many others without success. I am not a programmer but I kind of understand the basics. My programming basically comes from finding snippets of code and altering them for my use. Please Help!
You are using 2 columns : SurveyedID, SurveyStatus in your 'select' expression while in 'group by' you are using only SurveyStatus which is not valid. All non-aggregate columns in select should be used in 'group by' as well. That is why by adding MIN() to those columns solved the error (which converted those non-aggregate columns to aggregate ones).
Adding "SurveyedID" also to your group by clause can resolve your issue here.
Also if your sole motive is to avoid duplicates , just use 'DISTINCT' before the list of columns in select expression

SQL query, sum of of entries with the same type(name)

Hello i've got 3 different databases which list some different stuff about books. Im looking to find a way to write a SQL function which gives me the sum of books selled in every subsidiary(branch) and only the ones where the total sum is bigger than 2700 + the genre has to be romance. Ive easily figured out the function :
SELECT name, SUM(num_sell) as 'numSum'
FROM subsidiary,subsidiarybook,book
WHERE genre= "Romance"
group by name
As you guys cant see all of the datastuff thats going around there, I just want to ask why im always only getting the different names of the branches with the exact same total output. I guess it just takes the total of the first one and not the actual sum belonging to the different names.
Output looks like following :
Amazonhive 5163400
Celestial Library 5163400
Cloudcast 5163400
Cosmic Library 5163400
Globalworld 5163400
Imaginetworks 5163400
Leopardworks 5163400
Quick Rooster Media 5163400
Radiantelligence 5163400
Royal Library 5163400
Sphinx Brews 5163400
Spring Harbor ... 5163400
Surge Records 5163400
Tiny Mermaid Arts 5163400
Triumphoods 5163400
Tucan Productions 5163400
These values should be different since the sum of these isnt the same for sure. Would appreciate the help. Also how can i check if the sum is > 2700 ? putting a " AND num_sell >2700" behind the where as it would work normally isnt working in this case.
There is much to learn from this query.
FROM subsidiary, subsidiarybook, book
Do NOT use commas between table names in the FROM clause. What this does is MULTIPLY every row of subsidiary by every row of subsidiarybook and then MULTIPLY that result by every row in book. This is why the sum(num_sell) is a constant of 5,163,400 in your current result.
Your FROM clause should look more like this:
FROM subsidiary
INNER JOIN subsidiarybook ON subsidiary.id = subsidiarybook.subsidiary_id
INNER JOIN book ON sb.book_id = book.id
Once you have corrected the joins (nb the joins shown above are done in ignorance of the actual column names of your tables!) then you should start to see better results in the sum(num_sell). To filter the result of any aggregation use a HAVING clause.
SELECT book.name, SUM(num_sell) as 'numSum'
FROM subsidiary
INNER JOIN subsidiarybook ON subsidiary.id = subsidiarybook.subsidiary_id
INNER JOIN book ON sb.book_id = book.id
GROUP BY book.name
HAVING SUM(num_sell) > 2700
Now, there may be more to learn. For example subsidiary does not appear to be necessary for the final result and maybe it can be simplfied to:
SELECT book.name, SUM(num_sell) as 'numSum'
FROM subsidiarybook
INNER JOIN book ON sb.book_id = book.id
GROUP BY book.name
HAVING SUM(num_sell) > 2700
But to know exactly how to help further we need to know much more about your tables.
eg. we do not know which table num_sell actually comes from
you are join the table with cross join thats why sum is always same.
please lean about SQL joins
Definition of Cross Join
The SQL CROSS JOIN produces a result set which is the number of rows in the first table multiplied by the number of rows in the second table.
The HAVING clause will filter the rows after the GROUP BY. Reference
Add HAVING SUM(num_sell) > 2700 after the GROUP BY to achieve the required filtering.
An understanding of the logical processing order of SELECT statements is a valuable tool. Reference

MS Access 2013, How to add totals row within SQL

I'm in need of some assistance. I have search and not found what I'm looking for. I have an assigment for school that requires me to use SQL. I have a query that pulls some colunms from two tables:
SELECT Course.CourseNo, Course.CrHrs, Sections.Yr, Sections.Term, Sections.Location
FROM Course
INNER JOIN Sections ON Course.CourseNo = Sections.CourseNo
WHERE Sections.Term="spring";
I need to add a Totals row at the bottom to count the CourseNo and Sum the CrHrs. It has to be done through SQL query design as I need to paste the code. I know it can be done with the datasheet view but she will not accept that. Any advice?
To accomplish this, you can union your query together with an aggregation query. Its not clear from your question which columns you are trying to get "Totals" from, but here's an example of what I mean using your query and getting counts of each (kind of useless example - but you should be able to apply to what you are doing):
SELECT
[Course].[CourseNo]
, [Course].[CrHrs]
, [Sections].[Yr]
, [Sections].[Term]
, [Sections].[Location]
FROM
[Course]
INNER JOIN [Sections] ON [Course].[CourseNo] = [Sections].[CourseNo]
WHERE [Sections].[Term] = [spring]
UNION ALL
SELECT
"TOTALS"
, SUM([Course].[CrHrs])
, count([Sections].[Yr])
, Count([Sections].[Term])
, Count([Sections].[Location])
FROM
[Course]
INNER JOIN [Sections] ON [Course].[CourseNo] = [Sections].[CourseNo]
WHERE [Sections].[Term] = “spring”
You can prepare your "total" query separately, and then output both query results together with "UNION".
It might look like:
SELECT Course.CourseNo, Course.CrHrs, Sections.Yr, Sections.Term, Sections.Location
FROM Course
INNER JOIN Sections ON Course.CourseNo = Sections.CourseNo
WHERE Sections.Term="spring"
UNION
SELECT "Total", SUM(Course.CrHrs), SUM(Sections.Yr), SUM(Sections.Term), SUM(Sections.Location)
FROM Course
INNER JOIN Sections ON Course.CourseNo = Sections.CourseNo
WHERE Sections.Term="spring";
Whilst you can certainly union the aggregated totals query to the end of your original query, in my opinion this would be really bad practice and would be undesirable for any real-world application.
Consider that the resulting query could no longer be used for any meaningful analysis of the data: if displayed in a datagrid, the user would not be able to sort the data without the totals row being interspersed amongst the rest of the data; the user could no longer use the built-in Totals option to perform their own aggregate operation, and the insertion of a row only identifiable by the term totals could even conflict with other data within the set.
Instead, I would suggest displaying the totals within an entirely separate form control, using a separate query such as the following (based on your own example):
SELECT Count(Course.CourseNo) as Courses, Sum(Course.CrHrs) as Hours
FROM Course INNER JOIN Sections ON Course.CourseNo = Sections.CourseNo
WHERE Sections.Term = "spring";
However, since CrHrs are fields within your Course table and not within your Sections table, the above may yield multiples of the desired result, with the number of hours multiplied by the number of corresponding records in the Sections table.
If this is the case, the following may be more suitable:
SELECT Count(Course.CourseNo) as Courses, Sum(Course.CrHrs) as Hours
FROM
Course INNER JOIN
(SELECT DISTINCT s.CourseNo FROM Sections s WHERE s.Term = "spring") q
ON Course.CourseNo = q.CourseNo

Query using COUNT returns records where the count is positive only

Good day everyone.
Consider this portion of a relational SQLite database:
floors(number) - rooms(number, #floorNumber)
I aim to query for the number of rooms per floor. This is my attempt:
select floors.number, count(rooms.floornumber)
from floors, rooms where floors.number=rooms.floornumber
group by floors.number, rooms.floornumber;
Example:
1|5
2|7
3|5
4|3
The issue is that I also would like the query to return records where the floor contains 0 rooms (for example floor number 5 exists in the "floors" table but isn't shown in the query result).
Your assistance is appreciated. Thank you.
Never use commas in the FROM clause. Always use proper, explicit JOIN syntax.
You need a LEFT JOIN, but you cannot even see what you need because of the way that your query is written.
select f.number, count(r.floornumber)
from floors f left join
rooms r
on f.number = r.floornumber
group by f.number;

Oracle SQL - Comparing AVG functions in WHERE

I'm trying to write a few Oracle SQL scripts for an assignment. I've managed to get all of it to work, except for one part. To summarize, I have to display data from 2 tables if the average of 1 column in table A is greater than the average of another column in table B. I realize you cannot include AVG functions in a WHERE clause or HAVING clause since it seems unable to properly access the data (from what I've read). When I exclude this clause, the script executes properly, so I'm confident there are no other errors.
I've tried writing it as follows but the error I get is ORA-00936: missing expression and it is just before the > sign. I thought this may be due to improper bracket placing but none of my attempts resolved this. Here is my attempt:
SELECT l.l_category, SUM(r.r_sold), AVG(l.l_cost)
FROM promos l
INNER JOIN sales r
ON r.promo_id = l.promo_id
GROUP BY l.l_category
HAVING (SELECT AVG(l.l_cost) OVER (PARTITION BY l.l_cost)) >
(SELECT AVG(r.r_sold) OVER (PARTITION BY r.r_sold));
I tried doing this without the OVER (PARTITION BY ...) as well as putting it into a WHERE clause but it didn't resolve the error. I'm pretty sure I need to put it into a SELECT statement somehow but I'm at a loss.
You do not need to use the OVER clause when applying the aggregate functions in the HAVING clause. Just use the aggregate functions on their own.
SELECT l.l_category, SUM(r.r_sold), AVG(l.l_cost)
FROM promos l
INNER JOIN sales r
ON r.promo_id = l.promo_id
GROUP BY l.l_category
HAVING HAVING AVG(l.l_cost) > AVG(r.r_sold)